Test if an argument starts with a particular string

conditionalsmacrosstrings

Is there a way in tex to test if an argument starts with some string or not?
And then extract the text that follows that start?

As an example, I want to define a command that makes a text bold if it starts with my and italic otherwise.

\transform{my big world}
% Returns "\textbf{big world}". 

\transform{our small world}
% Returns "\textit{small world}". 

\transform{your world}
% Returns \textit{world}

% It would be great if the test is case insensitive 
\transform{My world} 
% Returns \textbf{world}

If possible, I prefer a method not using expl3 (I don't understand it enough to tinker with it).

The answers here gobbles a single character, which I can use for every character of my string. But that would get unwieldy rather quickly for long strings.

Best Answer

If your first word is always separated from the rest by a space, you can do with the following code:

\documentclass{article}

\makeatletter
\newcommand{\transform}[1]{\transform@#1\@nil}
\def\transform@@prefix{my}
\def\transform@#1 #2\@nil{%
  \lowercase{\def\transform@@start{#1}}%
  \ifx\transform@@start\transform@@prefix
    \textbf{#2}%
  \else
    \textit{#2}%
  \fi
}
\makeatother

\begin{document}

\transform{my big world} should return \textbf{big world}.

\transform{our small world} should return \textit{small world}.

\transform{your world} should return \textit{world}

\transform{My world} should return \textbf{world}

\end{document}

The first word is isolated and its lowercase version is matched with my.

enter image description here

Since you want a colon, rather than a space, it's possible to manage the absence of a prefix.

\documentclass{article}

\makeatletter
\newcommand{\transform}[1]{\transform@#1::\@nil}
\def\transform@@prefix{my}
\def\transform@#1:#2:#3\@nil{%
  \if\relax\detokenize{#2}\relax
    % no colon in #1
    \textit{#1}%
  \else
    \lowercase{\def\transform@@start{#1}}%
      \ifx\transform@@start\transform@@prefix
        \textbf{#2}%
      \else
        \textit{#2}%
      \fi
  \fi
}
\makeatother

\begin{document}

\transform{my:big world} should return \textbf{big world}.

\transform{our:small world} should return \textit{small world}.

\transform{your:world} should return \textit{world}

\transform{My:world} should return \textbf{world}

\transform{world} should return \textit{world}

\end{document}

enter image description here

An expl3 version, which is also (almost) fully expandable (it is not really because of \textit and \textbf, but we can use \text_expand:n to take care of that.

\documentclass{article}

\ExplSyntaxOn

% just for the final test
\cs_new_eq:NN \textexpand \text_expand:n
%%%

\NewExpandableDocumentCommand{\transform}{sm}
 {
  \IfBooleanTF{#1}
   {
    \tohiko_transform:V #2
   }
   {
    \tohiko_transform:n { #2 }
   }
 }

\cs_new:Npx \tohiko_transform:n #1
 {% colons are special in expl3
  \exp_not:N \__tohiko_transform:w #1 \c_colon_str \c_colon_str \exp_not:N \q_stop
 }
\cs_generate_variant:Nn \tohiko_transform:n { V }

\use:x
 {% colons are special in expl3
  \cs_new:Npn \exp_not:N \__tohiko_transform:w 
    ##1 \c_colon_str ##2 \c_colon_str ##3 \exp_not:N \q_stop
 }
 {
  \tl_if_empty:nTF { #2 }
   {
    \__tohiko_transformed:Nn \textit { #1 }
   }
   {
    \__tohiko_transform:nn { #1 } { #2 }
   }
 }

\cs_new:Npn \__tohiko_transform:nn #1 #2
 {
  \str_if_eq:eeTF { \str_lowercase:n { #1 } } { my }
   {
    \__tohiko_transformed:Nn \textbf { #2 }
   }
   {
    \__tohiko_transformed:Nn \textit { #2 }
   }
 }

\cs_new:Npn \__tohiko_transformed:Nn #1 #2
 {
  #1{\tl_trim_spaces:n{#2}}
 }

\ExplSyntaxOff

\newcommand{\testA}{my:hello world}
\newcommand{\testB}{our:hello world}

\begin{document}

\transform{my: big world} should return \textbf{big world}.

\transform{our:small world} should return \textit{small world}.

\transform{your:world } should return \textit{world}.

\transform{My:world} should return \textbf{world}.

\transform{world} should return \textit{world}.

\transform*{\testA} should return \textbf{hello world}.

\transform*{\testB} should return \textit{hello world}.

\edef\test{\textexpand{\transform{my: big world}}}
\texttt{\meaning\test}

\edef\test{\textexpand{\transform*{\testB}}}
\texttt{\meaning\test}

\end{document}

enter image description here

Related Question