21

I've got a define such as \def\doctype{SomeString}. \doctype can take on one of five values. I want to do something like a switch statement in a programming language, i.e. (pseudocode):

switch (\doctype) {
    case 'SomeString1': some text here
    case 'SomeString2': some different text here
    ...
}

(I don't need a default/else/otherwise case.) I tried doing this in LaTeX with:

\documentclass{article}

\usepackage{etoolbox}

\def\doctype{SomeString1}

\newenvironment{switchdoctype}[0]{%
  \newcommand{\case}[2]{\ifdefequal{\doctype}{##1}{##2}{}}%
}{}

\begin{document}

\begin{switchdoctype}
  \case{SomeString1}{some text here}
  \case{SomeString2}{some different text here}
\end{switchdoctype}

\end{document}

This gives an error: ERROR: Argument of \@secondoftwo has an extra }. I gather this is some sort of problem with using \ifdefequal. How can I make this work? I suspect it's some trick of expansion but I can't make this work with my limited knowledge of [La]TeX; I'm interested in learning something from making this work.

MacTeX 2010 here, which is based on TeX Live 2010 AFAIK. Thanks!

P.S.: boolexpr has a \switch but I can't use it because it conflicts badly with etoolbox (and BibLaTeX depends on etoolbox as far as I can tell). I have reported this incompatibility to the author listed in boolexpr's documentation.

5 Answers 5

13

From your description, I think you want \ifdefstring, as you need to compare one macro with one definition of a macro. \ifdefequal is for testing two macros for equivalence.

1
  • 1
    Holy crap that is embarrassing. You are right. I knew of the existence of both of these commands in my head, but I obviously got them switched around in the course of coming up with this code. Thanks!
    – dsedivec
    Commented Nov 8, 2010 at 22:06
19

Just for future reference, expl3 has nice switch/case statement constructs:

\str_case:nnF {\doctype}
{
   {SomeString1} {some~ text~ here}
   {SomeString2} {some~ different~ text~ here}
}
{else~ clause}

Variations are also provided with integers, dimensions, and token lists; e.g.,

\int_case:nnF{2*5}{
  {5}{Small}
  {4+6}{Medium}
  {-2*10}{Negative}
}{Other}
6
  • Nice indeed! Is there a reason for all those ~s? Commented Nov 11, 2010 at 9:19
  • 3
    In expl3 code, spaces are ignored, so if you want to print a string, ~ is used as a space. Commented Nov 11, 2010 at 11:20
  • Thank you very much! I skimmed expl3 the other day but didn't see anything that would help me. texdoc l3prg was just bringing up expl3.pdf. I have since learned to ask for source3 which appears to be a very comprehensive reference document. I'm excited to see all this stuff, especially all the standardized names. (And ignoring spaces also seems very kind to people writing commands.) If anyone in a position to do so reads this: it might be nice to mention the existence of source3 in the expl3 document. (My PDF reader didn't find that string.)
    – dsedivec
    Commented Nov 11, 2010 at 19:23
  • @dsedivec Thanks for the feedback; I've added a pointer like you suggest. Commented Nov 13, 2010 at 13:07
  • I think it would be nice to include an MCVE with this expl3 code. Commented May 14, 2021 at 20:29
11

Case statements can also be implemented with the xstring package:

enter image description here

\documentclass{article}
\usepackage{xstring}

\newcommand{\CheckCase}[1]{%
    \par\noindent%
    \IfEqCase*{#1}{%
    {Some String 1}{matched case 1}%
    {Some String 2}{matched case 2}%
    {Some String 3}{matched case 3}%
    {Some String 4}{matched case 4}%
    {Some String 5}{matched case 5}%
    }[Did not match any given case!!]%
}%

\begin{document}
    \CheckCase{Some String 1}
    \CheckCase{Some String 2}
    \CheckCase{Some String 3}
    \CheckCase{Some String 4}
    \CheckCase{Some String 5}
    \CheckCase{Some String 6}
\end{document}
3
  • I went down this path, but then it turned out that it can't do the following, for example. If I want to replace the first argument to \rule{1em}{2em} by an \IfEqCase, to output 5em or 10em etc., it won't work. As far as I can tell, this is because, as the xstring manual says, these macros are not purely expandable. I'm assuming this means that there is nothing we can do to have the \IfEqCase as the first argument to \rule be expanded before \rule is processed. So we can't use this as freely as \if, \else, \fi, etc. Correct me if I'm wrong! Commented Feb 8, 2016 at 10:02
  • @EvgeniSergeev: Sorry, but I am not very knowlegeable in regards to expansion related issues. I'd recommend you post a new question. I think you can do what you want using the optional parameter at the end of most of the xstring macros, but would need a MWE to make an attempt. Commented Feb 8, 2016 at 10:25
  • It seems the optional parameter isn't available for the comparison macros in xstring (I've just tried it to make sure). I'm more or less convinced that this will require too many tricks to make work, so I'll go with one of the other options. Commented Feb 8, 2016 at 10:41
9

For switching on identifiers, it's simplest to use the primitive \ifcase:

\documentclass{article}

\def\typeone{1}
\def\typetwo{2}

\begin{document}

\let\doctype=\typeone

\ifcase\doctype
  \or some text here %matches \typeone
  \or some different text here % matches \typetwo
\else you didn't want an else case, but it's no trouble to put in
\fi

\end{document}

If you want to convert strings into your type numbers, you can use \csname ...\endcsname; e.g., \csname typeone\endcsname will expand into 1, matching the first case.

3
  • Thanks, this is pretty good looking. I may have to play with this in the future.
    – dsedivec
    Commented Nov 8, 2010 at 22:06
  • 2
    No need for etoolbox here, I believe. Commented Apr 2, 2011 at 18:13
  • @Brune: Or indeed Latex. (Only just noticed your comment) Commented Mar 29, 2012 at 12:00
1

With functional package you can write this (it is a rewrite of Will Robertson's answer):

\documentclass{article}
\usepackage{functional}
\begin{document}

\def\doctype{SomeString1}

\StrCaseF {\Value\doctype} {
  {SomeString1} {\Result{Some Text}}
  {SomeString2} {\Result{some Different Text}}
}{\Result{Other Text}}

\IntCaseF {2*5} {
  {5}     {\Result{Small}}
  {4+6}   {\Result{Medium}}
  {-2*10} {\Result{Negative}}
}{\Result{Other}}

\end{document}

You must log in to answer this question.

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