# String comparison

\documentclass{article}
\usepackage{xifthen, xstring}

\newcommand{\IfOne}[3]{
\if\TokenIsIn#1
#2
\else
#3
\fi
}

\newcommand{\IfTwo}[3]{
\ifthenelse{\equal{\TokenIsIn}{#1}}{#2}{#3}
}

\newcommand{\IfThree}[3]{
\IfBeginWith{\TokenIsIn}{#1}{#2}{#3}
}
\newcommand{\TokenIsIn}{}
\newcommand{\settok}[1]{\global\let\TokenIsIn=#1}

\settok{a}

\begin{document}
\IfOne{a}{Yes}{No}\\
\IfTwo{a}{Yes}{No}\\
\IfThree{a}{Yes}{No}
\end{document}


Output

Yes
No
No


Why do the \IfTwo and \IfThree return No?

With \let\TokenIsIn=a, the control sequence \TokenIsIn becomes an unexpandable token; more precisely, it becomes an “implicit a”.

The tests \if\TokenIsIn a and \ifx\TokenIsIn a return true, but \ifthenelse makes the comparison in a different way; basically, \ifthenelse{\equal{X}{Y}} does something like

\edef\first{X}\edef\second{Y}\ifx\first\second


and this test returns false when X is \TokenIsIn and Y is a, because \first and \second don't have the same first level expansion: an implicit token is not the same as the token.

For \IfBeginWith the situation is a bit more complicated, but essentially the test fails because something like \edef\first{\TokenIsIn} is performed as well and, in \edef, \TokenIsIn is not changed into a.

With \ifthen and \IfBeginWith only explicit token should be used.

The three tests return true if you do

\newcommand{\settok}[1]{\gdef\TokenIsIn{#1}}


From another angle, the stringstrings package is very slow and is primarily intended for regular expressions. But if your problem is of that style, then it has some useful routines:

\documentclass{article}

\usepackage{stringstrings}

\begin{document}

\findchars{\mystring}{a} a's found in string

Position \whereischar{\mystring}{a} is where the first a' is found

\testmatchingchar{\mystring}{3}{a}
Character 3 \ifmatchingchar is \else is not \fi an a'.

\testmatchingchar{\mystring}{4}{a}
Character 4 \ifmatchingchar is \else is not \fi an a'.
\end{document}


I see some stray spaces are being produced by the \whereischar macro

\IfBeginWith uses this code (shown by \meaning\IfBeginWith)

\long macro:->\@ifstar {\let \@xs@assign \@xs@expand@and@detokenize
\@xs@IfBeginWith@@ }{\let \@xs@assign \@xs@expand@and@assign \@xs@IfBeginWith@@


i.e. it does expansion and detokenization of the input code \TokenIsIn, but \if... does expansion until it finds non-expandable tokens, which is the case (at least I think so) with \global\let\...=#1, which isn't expandable and it can't evaluate to be true (or 'No' here).

However, using a \newtoks register and expanding (or better: making it expandable) it within \TokenIsIn with \the\MyToken does not keep \if... from expanding the construct.

See the example output for the letter b, which should yield No for all macros.

\documentclass{article}
\usepackage{xifthen, xstring}

\newcommand{\IfOne}[3]{%
\if\TokenIsIn#1
#2%
\else
#3%
\fi
}

\newcommand{\IfTwo}[3]{%
\ifthenelse{\equal{\TokenIsIn}{#1}}{#2}{#3}%
}

\newcommand{\IfThree}[3]{%
\IfBeginWith{\TokenIsIn}{#1}{#2}{#3}%
}

\newcommand{\TokenIsIn}{\the\MyToken}

\newtoks\MyToken

\newcommand{\settok}[1]{\MyToken={#1}}%

\settok{a}

\begin{document}

\IfOne{a}{Yes}{No}

\IfTwo{a}{Yes}{No}

\IfThree{a}{Yes}{No}

\IfOne{b}{Yes}{No}

\IfTwo{b}{Yes}{No}

\IfThree{b}{Yes}{No}

\end{document}


• Can you comment on what is the issue? – Miheer Apr 14 '16 at 18:30
• @Miheer: I've done so -- I wasn't finished with this 'answer' -- it's usual to post a working code first and then adding explanations – user31729 Apr 14 '16 at 18:35
• Sorry, I might sound naive as I am just a beginner to tex. Does this mean that \let is not a reliable way to assign variables? Or is it that the commands in xifthen and xstring packages are not robust? – Miheer Apr 14 '16 at 19:09
• @Miheer: \let\...` is good for assigning macros to each other, making a copy of the macro thereby (there are other applications too), but I doubt its usefulness for tokens. (tokens are no macros) – user31729 Apr 14 '16 at 19:12