TeX - LaTeX Asked by NVaughan on February 27, 2021
Please consider the following MWE:
documentclass{article}
usepackage[utf8]{inputenc}
usepackage{etoolbox}
newcommand*{convertlang}[1]{%
ifstrequal{#1}{es}{spanish}{%
ifstrequal{#1}{lat}{latin}{%
ifstrequal{#1}{eng}{english}{%
ifstrequal{#1}{deu}{german}{%
ifstrequal{#1}{enm}{spanish}{% else
% use English as foreign default
english}}}}}}%
newcommand*{langtest}[1]{%
deftemp{convertlang{#1}}%
ifstrequal{temp}{spanish}{True}{False}%
}
begin{document}
Testing: convertlang{es} % yields: spanish
langtest{es} % should yield: True
end{document}
The command convertlang
takes an ISO 8859 language code (es
, eng
, etc.) and converts it into a babel language name (spanish
, english
, etc.). This works fine.
The problem is with langtest
, which compares a string (spanish
) with the result of transforming its argument (#1
) using convertlang
.
There must be a problem in the expansion of convertlang
and/or of #1
there, buy I don’t understand the fundamentals of TeX macro expansion.
I tried doing this:
newcommand*{langtest}[1]{%
edeftemp{convertlang{#1}}%
ifstrequal{temp}{spanish}{True}{False}%
}
expecting that temp
gets the expanded value of its argument. But this doesn’t work either.
How can I fix this?
You can use the expandable and expanding string equality test pdfstrcmp
(for portability use pdf@strcmp
from pdftexcmds
, see for example Are there any "if" commands like "ifnum" in LaTeX?). That command expands its test arguments and is itself expandable. (The latter is always nice, the former is not always convenient [cf. https://tex.stackexchange.com/q/230878/35864], but is what we want here.)
documentclass{article}
usepackage[utf8]{inputenc}
usepackage{etoolbox}
usepackage{pdftexcmds}
makeatletter
newcommand*{IfStrEqualTF}[2]{%
ifnumpdf@strcmp{#1}{#2}=z@
expandafter@firstoftwo
else
expandafter@secondoftwo
fi}
makeatother
newcommand*{convertlang}[1]{%
IfStrEqualTF{#1}{es}
{spanish}
{IfStrEqualTF{#1}{lat}
{latin}
{IfStrEqualTF{#1}{eng}
{english}
{IfStrEqualTF{#1}{deu}
{german}
{IfStrEqualTF{#1}{enm}
{spanish}
{english}}}}}}
newcommand*{langtest}[1]{%
IfStrEqualTF{convertlang{#1}}{spanish}
{True}
{False}}
begin{document}
Testing: convertlang{es} % yields: spanish
langtest{es} % should yield: True
langtest{en} % should yield: False
end{document}
Some more details about the MWE and why it doesn't do the desired thing.
First of all, etoolbox
's ifstrequal
is defined with newrobustcmd
. It is therefore robust and not expandable. That means that
edeftemp{convertlang{#1}}
does not actually save the long language name in temp
as we would have hoped. It just saves a cascade of ifstrequal
tests. This means that temp
does not contain a simple string.
edeftemp{convertlang{es}}%
showtemp
gives
> temp=macro: ->ifstrequal {es}{es}{spanish}{ifstrequal {es}{lat}{latin}{ifstrequal {es}{eng}{english}{ifstrequal {es}{deu}{german}{ifstrequal {es}{enm}{spanish}{english}}}}}.
You need a string equality test that is expandable to allow convertlang{#1}
to expand to the language name in an edef
.
pdf@strcmp
comes in handy here, since its string comparison is expandable, meaning that a command defined via this equality test can expand to the result of the comparisons in an edef
.
The second issue is that ifstrequal
doesn't expand its arguments, so even if temp
contained only a string, the test wouldn't quite work as intended
deftemp{spanish}%
ifstrequal{temp}{spanish}{True}{False}%
still gives 'False', since temp
is not a string equal to spanish
, it expands to a string equal to spanish
, that is a small but significant difference.
There are several possible ways around that. Depending on what you can guarantee about temp
it would be enough to say
expandafterifstrequalexpandafter{temp}{spanish}{True}{False}%
or
ifdefstring{temp}{spanish}{True}{False}%
if you know that temp
expands to a string in one expansion step. If more steps are required or you want full expansion, other tricks are needed.
pdf@strcmp
helps here, because it just completely expands its argument. This means that as long as temp
does not contain anything that blows up in an expansion context, its 'ultimate expanded string value' can be compared. You need not worry about expanding it first for the test.
Correct answer by moewe on February 27, 2021
I wouldn't use long nested if-tests. This is difficult to expand.
documentclass{article}
ExplSyntaxOn
tl_const:Nn c__nvaughan_convert_es_tl{spanish}
tl_const:Nn c__nvaughan_convert_lat_tl{latin}
tl_const:Nn c__nvaughan_convert_eng_tl{english}
tl_const:Nn c__nvaughan_convert_deu_tl{german}
tl_const:Nn c__nvaughan_convert_enm_tl{spanish}
newcommand*{convertlang}[1]
{
tl_if_exist:cTF {c__nvaughan_convert_#1_tl}
{ tl_use:c {c__nvaughan_convert_#1_tl} }
{ english}
}
newcommand*{langtest}[1]{%
str_if_eq:eeTF {convertlang{#1}}{spanish}
{True}{False}}
ExplSyntaxOff
begin{document}
Testing: convertlang{es} % yields: spanish
convertlang{lat} convertlang{blub}
langtest{es} % should yield: True
end{document}
Answered by Ulrike Fischer on February 27, 2021
I'd use the simpler interface of expl3
with str_case:nnF
documentclass{article}
usepackage{xparse}
ExplSyntaxOn
NewExpandableDocumentCommand{convertlang}{m}
{
nvaughan_convertlang:n { #1 }
}
cs_new:Nn nvaughan_convertlang:n
{
str_case:nnF { #1 }
{
{es}{spanish}
{lat}{latin}
{eng}{english}
{deu}{german}
{enm}{spanish}
}
{english}
}
NewExpandableDocumentCommand{langtest}{m}
{
str_if_eq:eeTF { nvaughan_convertlang:n { #1 } } { spanish } { True } { False }
}
ExplSyntaxOff
begin{document}
Testing: convertlang{es} % yields: spanish
langtest{es} should yield: True
langtest{lat} should yield: False
end{document}
Answered by egreg on February 27, 2021
Get help from others!
Recent Questions
Recent Answers
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP