TransWikia.com

Problem with command expansion

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?

3 Answers

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}

Testing: spanish//True//False


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}

enter image description here

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}

enter image description here

Answered by egreg on February 27, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP