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.

2
  • \ifstrequal does not expand its arguments.
    – egreg
    Aug 15, 2017 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. Aug 15, 2017 at 13:09

2 Answers 2

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

1
  • Thanks Ulrike, this worked perfectly for me, even when I nest the macros. Aug 15, 2017 at 15:49
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

4
  • He is not comparing \process{\a} but only \a with Fridge. Aug 15, 2017 at 13:31
  • @UlrikeFischer Yes, that's right.
    – egreg
    Aug 15, 2017 at 13:35
  • Hi Greg, thanks for your solution! I don't know what expl3 is, and when I tried your code, my compiler didn't like it. Aug 15, 2017 at 15:49
  • @JamieVicary First update your TeX distribution.
    – egreg
    Aug 15, 2017 at 15:59

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .