3

I am trying to use xstring's \IfStrEqCase to switch between cases. It seems to work fine except for the case where the parameter for the switch is a macro with an optional parameter:

\MySwitch{$\MyMacro[optional]{a - b}$}

The problematic line is commented out in the MWE. Once this works as desired, the last line in the output should be duplicated:

enter image description here

The code within the \MySwitch is used often for different cases.

Code:

\documentclass{article}
\usepackage{amsmath}
\usepackage{xstring}
\usepackage{xparse}

\NewDocumentCommand{\MyMacro}{o m}{\IfNoValueTF{#1}{#2}{\text{#1: } #2}}%

\newcommand*{\MySwitch}[1]{% \IfStrEqCase{#1}{% {plain text}{text: #1}% {$x^2$}{math a: #1}% {$\MyMacro{a - b}$}{math b: #1}% {$\MyMacro[optional]{a - b}$}{math c: #1}% }[Error: Invalid input: #1]% }

\begin{document} \MySwitch{plain text}

\MySwitch{$x^2$}

\MySwitch{$\MyMacro{a - b}$}

math c: $\MyMacro[optional]{a - b}$%% <-- Following should produce this output

%\MySwitch{$\MyMacro[optional]{a - b}$}% <--- This is the problem

\end{document}

Peter Grill
  • 223,288
  • One might argue that this is http://tex.stackexchange.com/questions/78414/bug-latex-misparses-nested-optional-arguments, although it's perhaps not obvious unless one knows the answer ... – Joseph Wright Dec 28 '16 at 10:08
  • Related: http://tex.stackexchange.com/questions/304458/how-do-i-nest-a-command-with-an-optional-argument – Steven B. Segletes Dec 28 '16 at 10:58

1 Answers1

5

The problem you have is a 'classic' one: the definition of optional arguments used by the LaTeX kernel (and most hand-written code) doesn't count up' square brackets. You therefore need to make sure that any place where optional arguments are nested is done with 'protection':

\documentclass{article}
\usepackage{amsmath}
\usepackage{xstring}
\usepackage{xparse}

\NewDocumentCommand{\MyMacro}{o m}{\IfNoValueTF{#1}{#2}{\text{#1: } #2}}%

\newcommand*{\MySwitch}[1]{%
    \IfStrEqCase{#1}{%
        {plain text}{text: #1}%
        {$x^2$}{math a: #1}%
        {$\MyMacro{a - b}$}{math b: #1}%
        {$\MyMacro[optional]{a - b}$}{math c: #1}%
    }[{Error: Invalid input: #1}]% CHANGE IS HERE
}

\begin{document}
\MySwitch{plain text}

\MySwitch{$x^2$}

\MySwitch{$\MyMacro{a - b}$}

math c: $\MyMacro[optional]{a - b}$%% <-- Following should produce this output


\MySwitch{$\MyMacro[optional]{a - b}$}% <--- This is the problem

\end{document}

Notice that I've added a pair of braces inside the optional argument so that #1 is 'safe' even if it itself contains [ ... ].

Where everything is set up by xparse this issue doesn't arise as it uses a definition for optional arguments that does match up square brackets: as a result, no extra steps are required.

Peter Grill
  • 223,288
Joseph Wright
  • 259,911
  • 34
  • 706
  • 1,036
  • Is there a simple fix to use \mathrm as in \MySwitch{$\MyMacro[optional]{\mathrm{a} - b}$}. I am getting a \GenericError. – Peter Grill Dec 28 '16 at 11:07
  • @PeterGrill That's a different question and is because \IfStrEqCase is trying to \edef something containing \mathrm. Easiest solution is \usepackage{etoolbox}\robustify\mathrm, as this makes the command engine robust. – Joseph Wright Dec 28 '16 at 12:06