TeX - LaTeX Asked by Nachiket on March 6, 2021
I’m trying to understand why the mymap
function in the following code does not produce any output when called with a variable in a for loop (see myloop
). It produces output when text is explicitly passed to it. See myloopb
. Sorry for the simple question, I wasn’t able to understand explanations of the if
and ifx
statements on stackexchange and other places. If it matters I’m using pdflatex from MikTex on Windows.
documentclass[12pt]{article}
usepackage{pgffor}
% define variables
defvala{aa}
defvalb{bb}
% this produces different output depending on #1
newcommand{mymap}[1]{
deftemparg{#1}
ifxtempargvala
Condition 1 is true
fi
ifxtempargvalb
Condition 2 is true
fi
}
newcommand{myloop}{
foreach myvar in {vala,valb}{
% this does not produce any output
mymap{myvar}
}
}
newcommand{myloopb}{
% this produces output
mymap{aa}
mymap{bb}
}
begin{document}
section{Using myloop does not produce output}
% no output
myloop
section{Using myloopb produces output}
% produces output
myloopb
end{document}
The issue is expansion here. ifx
tests whether the two following macros (if macros are passed) have the same meaning. In the first case temparg
has the meaning macro:->myvar
, whereas vala
has the meaning macro:->aa
and valb
is macro:->bb
.
Your myvar
has macro:->vala
and macro:->valb
as meaning in your loop. If you expand it twice before mymap
takes its argument, you get the correct meaning of temparg
. You can trigger earlier expansion with expandafter<tokA><tokB>
, which will expand <tokB>
before <tokA>
is expanded. So inside your loop use expandafterexpandafterexpandaftermymapexpandafterexpandafterexpandafter{myvar}
.
If your input is always fine to be fully expanded (it is in your example), you could use edeftemparg{#1}
instead, which is much cleaner than the expandafter
-chain proposed above.
documentclass[12pt]{article}
usepackage{pgffor}
% define variables
defvala{aa}
defvalb{bb}
% this produces different output depending on #1
newcommand{mymap}[1]{%
edeftemparg{#1}%
ifxtempargvala
Condition 1 is true%
fi
ifxtempargvalb
Condition 2 is true%
fi
}
newcommand{myloop}{%
foreach myvar in {vala,valb}{%
% this does not produce any output
mymap{myvar}%
}%
}
newcommand{myloopb}{%
% this produces output
mymap{aa}%
mymap{bb}%
}
begin{document}
section{Using myloop does not produce output}
% no output
myloop
section{Using myloopb produces output}
% produces output
myloopb
end{document}
Correct answer by Skillmon on March 6, 2021
You can define a general purpose string case comparison.
documentclass[12pt]{article}
usepackage{pgffor}
% a string comparison function
ExplSyntaxOn
NewExpandableDocumentCommand{StringCaseTF}{mm+m+m}
{% #1 = string input, #2 = cases,
% #3 = code to execute after a match
% #4 = code to execute after no match
str_case_e:nnTF { #1 } { #2 } { #3 } { #4 }
}
ExplSyntaxOff
% define variables (not with def)
newcommandvala{aa}
newcommandvalb{bb}
% this produces different output depending on #1
newcommand{mymap}[1]{%
StringCaseTF{#1}{
{vala}{Condition 1 is true}
{valb}{Condition 2 is true}
}{par There was a match!}{par There was no match!}%
par
}
newcommand{myloop}{%
foreach myvar in {vala,valb,x}{
% this does not produce any output
mymap{myvar}
}
}
begin{document}
myloop
end{document}
Load xparse
if you don't have the most recent LaTeX kernel.
The third or fourth arguments to StringCaseTF
can be left empty, of course.
Answered by egreg on March 6, 2021
Get help from others!
Recent Answers
Recent Questions
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP