TeX - LaTeX Asked by Count Zero on January 17, 2021
I’d like to have command built around a switch-case
environment in LaTeX, much like the example below:
documentclass{article}
usepackage{xstring}
newcommand{dothis}[1]{%
IfStrEqCase{#1}{{a}{so you typed a}
{b}{now this is b}
{c}{you want me to do c?}}
[nada]
}
begin{document}
dothis{a}
dothis{b}
dothis{c}
dothis{e}
end{document}
My problem with it is that it requires the xstring
package. Is there any other way to do this? Preferably without loading additional packages and avoiding disgraceful thickets of if-else-fi
statements?
The question asks to avoid packages, so while this is the method used by expl3
in str_case:nnF
I have recoded it with minimal support. The only package I've used is pdftexcmds
, which is needed as the pdfstrcmp
primitive from pdfTeX is called strcmp
by XeTeX and has to be implemented in Lua for LuaTeX. This is easy enough to do without the package, but obscures the method: ask a separate question if required!
The general idea here is to set up a comparison loop in which the test is done expandably by pdfstrcmp
. The test string is passed every time, with the 'true' string inserted if there is a match by the 'tidy up' code. If there is no match at all then the 'else' code is inserted. The romannumeral
business means that it always requires exactly two expansions to do the work here:
documentclass{article}
usepackage{pdftexcmds}
makeatletter
newcommand*{dothis}[1]{%
stringcases
{#1}%
{%
{a}{so you typed a}%
{b}{now this is b}%
{c}{you want me to do c?}%
}%
{[nada]}%
}
newcommand{stringcases}[3]{%
romannumeral
str@case{#1}#2{#1}{#3}q@stop
}
newcommand{str@case}[3]{%
ifnumpdf@strcmp{unexpanded{#1}}{unexpanded{#2}}=z@
expandafter@firstoftwo
else
expandafter@secondoftwo
fi
{str@case@end{#3}}
{str@case{#1}}%
}
newcommand{str@case@end}{}
longdefstr@case@end#1#2q@stop{z@#1}
makeatother
begin{document}
dothis{a}
dothis{b}
dothis{c}
dothis{e}
end{document}
Correct answer by Joseph Wright on January 17, 2021
The following is from catoptions package. The following ifcasse
is cptifcasse
in catoptions package. I think Count Zero should simply load an existing package for his task.
documentclass{article}
usepackage{pdftexcmds}
makeatletter
longdefam@alltoendif#1endif{unexpanded{#1}}
longdefam@domatchcode#1#2endif{unexpanded{#1}}
longdefamifcond#1fi{csname @#1firstelse secondfi oftwoendcsname}
longdefamifstrcmp#1#2{%
amifcondif0pdf@strcmp{detokenize{#1}}{detokenize{#2}}fi
}
defifcasse#1#2{%
amifstrcmp{#1}ifnone{%
am@alltoendif
}{%
amifstrcmp{#1}endif{}{%
amifstrcmp{#2}ifnone{%
am@alltoendif
}{%
amifstrcmp{#2}endif{}{am@ifcasse{#1}{#2}}%
}%
}%
}%
}
defam@ifcasse#1#2#3{%
amifstrcmp{#3}ifnone{%
am@alltoendif
}{%
amifstrcmp{#3}endif{}{%
#1{#2}{#3}am@domatchcode{am@ifcasse@i{#1}{#2}}%
}%
}%
}
defam@ifcasse@i#1#2#3{am@ifcasse{#1}{#2}}
% The user can also define his own logical test command and pass it as the first
% argument of ifcasse. For example, we define ifnumtest:
defifnumtest#1#2{amifcondifnum#1#2fi}
% We rewrite Count Zero's macro:
newcommand*{dothis}[1]{%
par
ifcasseamifstrcmp{#1}%
{a}{so you typed a}
{b}{now this is b}
{c}{you want me to do c?}
ifnone
[no match]%
endif
}
makeatother
begin{document}
dothis{a}
dothis{b}
dothis{c}
dothis{e}
% Weird test that correctly gives x as 'empty':
edefx{%
ifcasseamifstrcmp{x}
endif
}
%showx
% Weird test that gives x as 'no match':
edefx{%
ifcasseamifstrcmp{x}
ifnone
[no match]%
endif
}
par``x''.
% Number test:
edefx{%
ifcasseifnumtest{2}
{=1}{equal to 2}
{<3}{less than 3}
{>4}{greater than 4}
ifnone
no match%
endif
}
par``x''.
end{document}
Answered by Ahmed Musa on January 17, 2021
Though it's most likely too late for the OP, I just worked out my own switch and thought I'd share it here for future readers. My solution uses solely the package xifthen
(ifthen
suffices too, but I already had xifthen
installed...).
% Switch implementation
usepackage{xifthen}
newcommand{ifequals}[3]{ifthenelse{equal{#1}{#2}}{#3}{}}
newcommand{case}[2]{#1 #2} % Dummy, so renewcommand has something to overwrite...
newenvironment{switch}[1]{renewcommand{case}{ifequals{#1}}}{}
% Example: Pick color by ID
newcommand{incolor}[2]{
begin{switch}{#1}
case{1}{color{red}}
case{2}{color{blue}}
case{3}{color{green}}
case{4}{color{black}}
#2
end{switch}
}
This code compiles perfectly fine in my TeXMaker (ofc. you'll need the color-package for this example, but it's not part of the switch). The example colors a given input in a color defined by an ID I chose (Usage: incolor{ID}{Content}
). I used it for shorthand notations of lots of things (e.g. lp1
, lp2
, ... for parentheses in different colors using newcommand{lp}[1]{incolor{#1}{langle}}
). Feel free to experiment ;)
I could imagine this to be expanded to a solution using only built-in control structures, but I've been too lazy for now to do so, yet ifx
and else
should do the trick.
Answered by Thev on January 17, 2021
Here is a solution via macro definitions (a single test makes the choice):
documentclass{article}
makeatletter
newcommandaddcase[3]{expandafterdefcsnamestring#1@case@#2endcsname{#3}}
newcommandmakeswitch[2][]{%
newcommand#2[1]{%
ifcsnamestring#2@case@##1endcsnamecsnamestring#2@case@##1endcsnameelse#1fi%
}%
}
makeatother
makeswitch[nada]dothis
addcasedothis{a}{so you typed a}
addcasedothis{b}{so you typed b}
addcasedothis{c}{you want me to do c?}
begin{document}
dothis{a}
dothis{b}
dothis{c}
dothis{e}
end{document}
Answered by Paul Gaborit on January 17, 2021
Based on the great answer by Thev and updated by MaxD I have implemented a default
command for switch. I used ifthen
package:
newboolean{default}
newcommand{case}{}
newcommand{default}{}
newenvironment{switch}[1]{%
setboolean{default}{true}
renewcommand{case}[2]{ifthenelse{equal{#1}{##1}}{%
setboolean{default}{false}##2}{}}%
renewcommand{default}[1]{ifthenelse{boolean{default}}{##1}{}}
}{}
Then implement it as such:
begin{switch}{program}
case{2}{twodayprogram}
case{4}{fourdayprogram}
default{first last missing programpagebreak}
end{switch}
in case anyone is curious, this was a program for an off-season sports conditioning program and was being looped with datatool
, the commands twodayprogram
and fourdayprogram
implement the program for a particular athlete
Answered by coachshea on January 17, 2021
In LuaTeX you can use Lua tables to emulate a switch statement.
% arara: lualatex
documentclass{article}
newcommand*dothis[1]{%
directlua{
local cases = {
a = "so you typed a",
b = "now this is b",
c = "you want to do c?"
}
if cases["luaescapestring{#1}"] string~= nil then
tex.sprint(cases["luaescapestring{#1}"])
else
tex.sprint("[nada]")
end
}
}
begin{document}
dothis{a}
dothis{b}
dothis{c}
dothis{d}
end{document}
Answered by Henri Menke on January 17, 2021
This is a simple extension to Thev's answer, adding support for a default case.
% Switch implementation
usepackage{xifthen}
newcommand{ifequals}[4]{ifthenelse{equal{#1}{#2}}{#3}{#4}}
newcommand{case}[2]{#1 #2} % Dummy, so renewcommand has something to overwrite...
newenvironment{switch}[1]{renewcommand{case}{ifequals{#1}}}{}
% Example: Pick color by ID
newcommand{incolor}[2]{
begin{switch}{#1}
case{1}{color{red}}{
case{2}{color{blue}}{
case{3}{color{green}}{
case{4}{color{black}}{
color{cyan}
}}}}
end{switch}
#2
}
Answered by Zalastax on January 17, 2021
There is the built-in ifcase
which works like a switch-case that interpret numbers. Because of this, I translated the strings 'a', 'b', 'c' to numbers 0, 1, 2. Note that the first case is 0. It don't need packages and is very simple.
documentclass{article}
newcommand{dothis}[1]{%
ifcase#1relax so you typed a % Case 0.
or now this is b % Case 1.
or you want me to do c? % Case 2.
else Default case.
fi
}
begin{document}
dothis{0}
dothis{1}
dothis{2}
dothis{3}
end{document}
Answered by Rodolfo FR on January 17, 2021
Get help from others!
Recent Answers
Recent Questions
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP