6

I have a large \foreach loop, and need to evaluate macros on the arguments. (These are string comparison macros, but maybe that doesn't matter.) Here's an example:

\documentclass{article}
\usepackage{tikz}
\usepackage{etoolbox}
\newcommand\process[1]{\ifstrequal{#1}{Fridge}{EQUAL}{UNEQUAL}}
\begin{document}
\foreach \a in {Fridge,Badger} {\process{\a} }
\end{document}

This produces the output UNEQUAL UNEQUAL. My desired output is EQUAL UNEQUAL.

In my real example I'm doing a simultaneous iteration over multiple variables (\foreach \a/\b in ...), and my macros take multiple parameters, not just one.

I'm not completely clueless; I know why this is happening, and I've tried hundreds of combinations of \expandafter, \edef, and so on, but without any success. I find this aspect of LaTeX extremely hard to understand.

Jamie Vicary
  • 11,098
  • \ifstrequal does not expand its arguments. – egreg Aug 15 '17 at 13:07
  • Hi @egreg, thanks for your comment. I don't really know what that means. I don't have to use \ifstrequal, I'd be happy to use some other macro that lets me test an argument for string equality. – Jamie Vicary Aug 15 '17 at 13:09

2 Answers2

7
\documentclass{article}
\usepackage{tikz}
\usepackage{etoolbox}
\newcommand\process[1]{\expandafter\ifstrequal\expandafter{#1}{Fridge}{EQUAL}{UNEQUAL}}
\begin{document}
\foreach \a in {Fridge,Badger} {\process{\a} }
\end{document}

enter image description here

Ulrike Fischer
  • 327,261
5

The manual of etoolbox says (section 3.6.3)

\ifstrequal{⟨string⟩}{⟨string⟩}{⟨true⟩}{⟨false⟩}
Compares two strings and executes ⟨true⟩ if they are equal, and ⟨false⟩ otherwise. The strings are not expanded in the test and the comparison is category code agnostic. Control sequence tokens in any of the ⟨string⟩ arguments will be detokenized and treated as strings.

In other words, you are comparing

\a

(a two character string) with Fridge and they're not equal at all. With expl3 you can access an expanding string comparison function:

\documentclass{article}
\usepackage{xparse}
\usepackage{tikz}

\ExplSyntaxOn
\NewExpandableDocumentCommand{\xifstrequal}{mmmm}
 {
  \str_if_eq_x:nnTF { #1 } { #2 } { #3 } { #4 }
 }
\ExplSyntaxOff

\newcommand\process[1]{\xifstrequal{#1}{Fridge}{EQUAL}{UNEQUAL}}

\begin{document}

\foreach \a in {Fridge,Badger} {\process{\a} }

\end{document}

A full expl3 version:

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewExpandableDocumentCommand{\xifstrequal}{mmmm}
 {
  \str_if_eq_x:nnTF { #1 } { #2 } { #3 } { #4 }
 }
\NewDocumentCommand{\listforeach}{mm}
 {
  \clist_map_inline:nn { #1 } { #2 }
 }
\ExplSyntaxOff

\newcommand\process[1]{\xifstrequal{#1}{Fridge}{EQUAL}{UNEQUAL}}

\begin{document}

\listforeach{Fridge,Badger}{\process{#1} }

\end{document}

Instead of using some dummy control sequence, the current item is denoted by #1.

Both codes produce the same output.

enter image description here

egreg
  • 1,121,712