1

I have a tex file with some of my own custom functions, one of which is a switch case function.
Because I use \input to call this file from other documents, I need the output variable to be local. However, I need a local variable to store the output while I iterate through the rest of the loop. Either that or abort the loop and go to the end of the function.

I am using tex maker and pdftex

\usepackage{xparse}
\usepackage{fp}
\usepackage{xstring}
\usepackage{ifthen}
\usepackage{printlen}
\usepackage{listofitems}
\usepackage{forloop}
\usepackage{pgffor}

\NewDocumentCommand\SwitchCase{m m}
{
    \setsepchar{,/-}
    \readlist\Cases{#2}
    \FPadd\CaseCount{\Caseslen}{0}
    \def\out{}
    \foreach \ct in {1,...,\CaseCount}
    {
        \ifthenelse{\equal{#1}{\Cases[\ct ,1]}}
        {
            \def\tmp{\Cases[\ct, 2]}
            %\tmp
            \def\out{\tmp}
        }
        {}
    }
    \out
}

%below is a sample of how this code would work
%not exactly how I would use it, but still valid example

\begin{document}

\SwitchCase{hello}{hel-1,he-2,hello-3,Hello-4}

\end{document}

Given the example, the function should return 3, however when I attempt to set the output variable in the loop, it returns either 0 or nothing.

This function has many possible uses in my documents therefore it has to be vague.

p.s. I apologize if any of the wording is awkward, I am not the best with syntax and word choice.

  • \foreach starts a group. So the local value of \out gets "forgotten". Either use \xdef\out{\tmp} (or \gdef\out{\tmp}) or use an ordinary \loop or another loop that does not use groups (you load more than enough packages for that;-). – user194703 Dec 9 '19 at 16:58
  • you are using a wild collection of different idioms, expl3, pgf for the loop ifthen for the conditional, fp for the arithmetic and tex primitive def!!! You are also missing a lot of % from ends of lines it would be simpler to write it just using expl3, however the main issue is that each iteration of a pgf loop is in a group so your \def do not survive, you could use gdef (or perhaps \xdef depending on what you want the code to do) but netter not to use a loop that groups the items. – David Carlisle Dec 9 '19 at 17:00
3

You can implement the functionality wthout using all the packages here:

\documentclass{article}

\makeatletter
\newcommand\SwitchCase[2]{%
  \def\tmpa{#1}%
  \@for\tmp:=#2\do{\expandafter\zz@switch\tmp\zz@switch}%
 }
 \def\zz@switch#1-#2\zz@switch{%
  \def\tmpb{#1}%
   \ifx\tmpa\tmpb#2\fi}

\makeatother

\begin{document}

\SwitchCase{hello}{hel-1,he-2,hello-3,Hello-4}

\end{document}
  • This is perfect. And it also works for delegating other functions. I have cases in which I have to load images, and it is easier to keep them all together, and therefore using the switch case helps significantly. – cdickstein Dec 9 '19 at 20:18
1

It's the usual problem: \foreach cycles are done in a group.

Also, you have to fully expand the replacement text of \tmp (but you don't need it and can define directly \out).

\documentclass{article}
\usepackage{xparse}
\usepackage{fp}
\usepackage{xstring}
\usepackage{ifthen}
\usepackage{printlen}
\usepackage{listofitems}
\usepackage{forloop}
\usepackage{pgffor}

\NewDocumentCommand\SwitchCase{m m}
 {%
    \setsepchar{,/-}%
    \readlist\Cases{#2}%
    \foreach \ct in {1,...,\Caseslen}
     {%
        \ifthenelse{\equal{#1}{\Cases[\ct ,1]}}
         {%
            \xdef\out{\Cases[\ct, 2]}
         }
         {}%
     }%
    \out
 }

\begin{document}

\SwitchCase{hello}{hel-1,he-2,hello-3,Hello-4}

\end{document}

This outputs 3.

Beware of unprotected end-of-lines that generate spaces that might not be ignored, depending on the context where the macro is called.

A shorter version using expl3:

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand\SwitchCase{m m}
 {
  \clist_map_inline:nn { #2 }
   {
    \__cdickstein_switchcase_item:nn { #1 } { ##1 }
   }
 }

\cs_new:Nn \__cdickstein_switchcase_item:nn
 {
  \__cdickstein_switchcase_item:nw { #1 } #2 \q_stop
 }

\cs_new:Npn \__cdickstein_switchcase_item:nw #1 #2 - #3 \q_stop
 {
  \str_if_eq:nnT { #1 } { #2 } { \clist_map_break:n { #3 } }
 }
\ExplSyntaxOff

\begin{document}

\SwitchCase{hello}{hel-1,he-2,hello-3,Hello-4}

\end{document}

This stops at the first match.

An expandable version that again stops at the first match.

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewExpandableDocumentCommand\SwitchCase{m m}
 {
  \__cdickstein_switchcase:nw { #1 } #2 , , \q_nil
 }

\cs_new:Npn \__cdickstein_switchcase:nw #1 #2 ,
 {
  \tl_if_blank:nTF { #2 }
   {
    \use_none:n
   }
   {
    \__cdickstein_switchcase_item:nw { #1 } #2 \q_stop
    \__cdickstein_switchcase:nw { #1 }
   }
 }
\cs_new:Npn \__cdickstein_switchcase_item:nw #1 #2 - #3 \q_stop
 {
  \str_if_eq:nnT { #1 } { #2 } { #3 \__cdickstein_swithcase_break:w }
 }

\cs_new:Npn \__cdickstein_swithcase_break:w #1 \q_nil {}
\ExplSyntaxOff

\begin{document}

\SwitchCase{hello}{hel-1,he-2,hello-3,Hello-4}

\SwitchCase{x}{x-1,y-2,x-3}

\end{document}
  • I've left an opening for you to do an expandable expl3 version:-) – David Carlisle Dec 9 '19 at 17:34
  • @DavidCarlisle Toobad, I got the green tick. – egreg Dec 9 '19 at 20:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.