[Tex/LaTex] String equality in \ifx conditional using output from concatenating macros

conditionalstex-core

Please consider the following MWE – where I try to test for string equality between an parameter, and a test string prepared by a macro:

\documentclass{article}

\def\testStr#1{IOIO#1}

\newcommand{\doTest}[1]{%
\edef\tmphwp{\testStr{XX}} %
\typeout{=\tmphwp=#1=} %
\ifx\tmphwp#1{%
\typeout{~equal}%
}\else{%
\typeout{!not equal}%
}\fi %
\typeout{ ^^J } % newline in terminal stdout
}

\begin{document}

\doTest{12}

\doTest{hello}

\doTest{IOIOXX}

\end{document}

Strangely, this seems to always determine strings are unequal – even if I enter specifically the right string – terminal log (from pdflatex) reports:

=IOIOXX=12=
!not equal


=IOIOXX=hello=
!not equal


=IOIOXX=IOIOXX=
!not equal

Hmm … I would have expected IOIOXX = IOIOXX ?!

Can anyone explain why am I not getting the expected results – and how to get the right comparison? Does this have maybe to do anything with catcodes?

Many thanks in advance for any answers,
Cheers!

Best Answer

The main thing to note is that \ifx compares, without expanding them, the two tokens that follow. Now let's slowly look at what \dotest{IOIOXX} expands to.

  1. \edef\tmphwp{\testStr{XX}} that's equivalent to \def\tmphwp{IOIOXX}

  2. \typeout{=\tmphwp=#1=} that prints on the screen =IOIOXX=IOIOXX=

  3. The conditional

    \ifx\tmphwp IOIOXX{%
      \typeout{~equal}%
    }\else{%
      \typeout{!not equal}%
    }\fi %
    \typeout{ ^^J } % newline in terminal stdout
    

which is false, because \tmphwp is different from I.

You're making a few other errors: your way of writing the code leaves a fair amount of spurious spaces; the true and the false branches of the conditional are not required to be in braces, which in most cases would even be wrong.

What to do in order to compare two strings? Put the one given as argument in the replacement test of a temporary macro:

\def\dotest#1{%
  \def\next{#1}%
  \ifx\tmphwp\next
    \typeout{EQUAL}%
  \else
    \typeout{NOT EQUAL}%
  \fi
}

where you already have set somewhere \tmphwp to expand to the "control string" (I don't see why you should set it when doing the test itself), say with

\def\tmphwp{IOIOXX}

Let's say that \tmphwp expands to IOIOXX: now \ifx will compare the two control sequences \tmphwp and \next which are equal, because they are both not \long, their parameter text is the same (empty) and they have the same replacement text (IOIOXX).

Conversely, \dotest{AA} would evaluate the test to false.

Related Question