# switch-case condition [duplicate]

There are only two clause in \ifthenelse—<then clause> and <clause>. If more than two test conditions are needed, the \ifthenelse has to be nested. This will make code awful and be hard to maintain. Is there a better way, for example, switch-case marco like this(like C language):

\switchconditon
{<case 1> <clause 1>}
{<case 2> <clause 2>}
{<case 3> <clause 3>}


an example by \ifthenelse:

\ifthenelse{\equal{#1}{ul}}%ul=upper left
{\let\position\AtPageUpperLeft}
{}
\ifthenelse{\equal{#1}{ll}}%ll=lower left
{\let\position\AtPageLowerLeft}
{}
\ifthenelse{\equal{#1}{pc}}%pc=paper center
{\let\position\AtPageCenter}
{}


Can you give a code to achive the last code function? Thank you.

## marked as duplicate by Werner, Stefan Pinnow, Troy, Schweinebacke, David CarlisleAug 14 '17 at 12:36

The expl3 programming layer of LaTeX3 comes with a lot of utility functions for such purposes. The model offers different datastructures and algorithms which operate on them. Some of them have a switch statement, see examples below.

For your use-case the \str_case:nn is appropriate. If no match is found an error is signalled.

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn

\msg_new:nnn
{ switchcase }
{ no-match }
{ There~is~no~entry~#1'~in~the~switch~statement! }

\NewDocumentCommand \switchcase { m m }
{
\str_case:nnF { #1 } { #2 } { \msg_error:nnn { switchcase } { no-match } { #1 } }
}

\ExplSyntaxOff

\newcommand\whatever[1]{%
\switchcase{#1}%
{
{ul}{\let\position\AtPageUpperLeft}
{ll}{\let\position\AtPageLowerLeft}
{pc}{\let\position\AtPageCenter}
}%
}

% Sentinel
\newcommand*\AtPageUpperLeft{AtPageUpperLeft}
\newcommand*\AtPageLowerLeft{AtPageLowerLeft}
\newcommand*\AtPageCenter   {AtPageCenter}

\begin{document}

\whatever{ul}\position

\whatever{ll}\position

\whatever{pc}\position

\whatever{rubbish}\position % error!

\end{document}


For macros you can use \tl_case:nn:

If you want to compare strings in a catcode agnostic fashion, use \str_case:nn

For integers there is \int_case:nn

For dimensions there is \dim_case:nn

• Thank you Menke. The Package expl3 must be declared? And could you show me how to use it through my updated code example. – lyl Aug 14 '17 at 7:45
• It seems a bit complicate. Anyway, many thanks again. I'll try to understand it. – lyl Aug 14 '17 at 10:15

Here is a fairly general switch case macro, based on expl3. The syntax is

\switchcondition[<type>]{<input>}[<other>]{<cases>}


where <type> is one among string, token, integer or dimen (default string), <input> is the argument to test against the cases, <other> is what to do if no case is matched, and <cases> is the list of cases in the form

{<case-1>}{<code-1>}
{<case-2>}{<code-2>}
[...]
{<case-n>}{<code-n>}


The macro is, by itself, fully expandable, but of course this feature can be exploited only if <other> and <code-k> are fully expandable for every case.

Here's an example.

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewExpandableDocumentCommand{\switchcondition}{O{string}mmO{}}
{
\use:c { lyl_#1_switch:nnn } { #2 } { #3 } { #4 }
}

\cs_new:Nn \lyl_string_switch:nnn
{
\str_case:nnF { #1 } { #2 } { #3 }
}
\cs_new:Nn \lyl_token_switch:nnn
{
\tl_case:nnF { #1 } { #2 } { #3 }
}
\cs_new:Nn \lyl_integer_switch:nnn
{
\int_case:nnF { #1 } { #2 } { #3 }
}
\cs_new:Nn \lyl_dimen_switch:nnn
{
\dim_case:nnF { #1 } { #2 } { #3 }
}
\ExplSyntaxOff

\newcommand{\placement}[1]{%
\switchcondition{#1}{
{ul}{\let\position\AtPageUpperLeft}
{ll}{\let\position\AtPageLowerLeft}
{ur}{\let\position\AtPageUpperRight}
{lr}{\let\position\AtPageLowerRight}
}[\let\position\ERROR]%
}

% whatever these should do
\providecommand{\AtPageUpperLeft}{APUL}
\providecommand{\AtPageLowerLeft}{APLL}
\providecommand{\AtPageUpperRight}{APUR}
\providecommand{\AtPageLowerRight}{APLR}
\providecommand{\ERROR}{ERROR}

\newcommand{\foo}[1]{%
\switchcondition[integer]{#1}{
{1}{One}
{20}{Twenty}
}[Uninteresting number]%
}

\begin{document}

\placement{ul}\texttt{\meaning\position}

\placement{ll}\texttt{\meaning\position}

\placement{ur}\texttt{\meaning\position}

\placement{lr}\texttt{\meaning\position}

\placement{xy}\texttt{\meaning\position}

\foo{1}

\foo{6*7}

\foo{3456}

\end{document}


• Thank you egreg. I need to learn more about the package xparse. – lyl Aug 14 '17 at 10:00

You can also just let TeX's csname hash table do the lookup for you so

\def\positionul{\let\position\AtPageUpperLeft}
\def\positionll{\let\position\AtPageLowerLeft}
\def\positionpc{\let\position\AtPageCenter}


then in the macro that you did not show, that wants to use #1 being ul, ll or pc just use

\csname position#1\endcsname


and it will execute \positionll if #1 is ll

• I think this is a good and simple solution. By the way, why the following code does not show "aaa"? \def\t1{aaa} \def\t2{bbb} \newcommand{\tttt}[1]{\csname t#1\endcsname} \tttt{1} – lyl Aug 14 '17 at 13:17
• \def\t1{aaa} defines \t followed by 1 you would need \expandafter\def\csname t1\endcsname{aaa} to access a macro named t1 – David Carlisle Aug 14 '17 at 13:59
• Thank you. I want to define a marco named "\t1" by input "expandafter\def\csname t1\endcsname{aaa}", then I want to get "aaa" by input \t1,but "aaa" did not show. why? – lyl Aug 15 '17 at 12:53
• @lyl same reason \t1 is the same as \t 1 the two tokens \t and 1 to access a command with name t1 you would need \csname t1\endcsname` – David Carlisle Aug 15 '17 at 13:08