我正在寻找一种巧妙的方法来switch
根据下一个输入字符编写语句,理想情况下,可以写:
\@switchnextchars
\@case{abc}{\typeout{You gave me an abc}}%
\@case{ab+}{\typeout{You gave me an ab+}}%
\@default{\typeout{Nothing that I heard of!}%
\@endswitch
但是也
\@ifnextchars{abc}{yes code}{no code}
甚至
\@ifnexttwochars{ab}{yes code}{no code}
会很有用。
答案1
\@ifnextchar
例如,构建测试循环的一种可能方法是
\makeatletter
\newtoks\my@toksa
\newtoks\my@toksb
\newcommand\@ifnextchars[3]{%
\def\my@tempa{#1}%
\def\my@tempb{#2}%
\def\my@tempc{#3}%
\def\my@tempd{}%
\@ifnextchars@aux@i
}
\newcommand*\@ifnextchars@aux@i{%
\def\my@tempe{\expandafter\my@tempb\my@tempd}%
\ifx\@empty\my@tempa\@empty
\else
\def\my@tempe{\@ifnextchars@aux@ii}%
\fi
\my@tempe
}
\newcommand*\@ifnextchars@aux@ii{%
\my@toksa\expandafter\expandafter\expandafter
{\expandafter\@car\my@tempa\@nil}%
\expandafter\@ifnextchar\the\my@toksa
{%
\expandafter\def\expandafter\@ifnextchars@aux@iii\the\my@toksa{%
\my@toksb\expandafter{\my@tempd}%
\edef\my@tempd{\the\my@toksb\the\my@toksa}%
\my@toksa\expandafter\expandafter\expandafter
{\expandafter\@cdr\my@tempa\@nil}%
\edef\my@tempa{\the\my@toksa}%
\@ifnextchars@aux@i
}%
\@ifnextchars@aux@iii
}
{\expandafter\my@tempc\my@tempd}%
}
\makeatother
(这可能不是最有效的实现。)正如您所见,这并不简单,因为 TeX 仅提供\futurelet
(基于此\@ifnextchar
构建),并且每次只处理一个标记。'cases' 系统是可行的,但并不美观,因为必须保存每个案例,并且每次使用标记重新插入进行测试。
答案2
xstring
包提供了一些用于字符串操作的函数,\IfStrEqCase
可用于此目的。使用 pdfTeX(latex
命令通常是 pdfTeX),您也可以使用它\pdfstrcmp
进行比较。这不像 那样有效\@ifnextchar
,但可能会有所帮助。
\documentclass{article}
\usepackage{xstring}
\begin{document}
\newcommand\test[1]{%
\IfStrEqCase{#1}{%
{a}{I got `a'}
{bb}{I got `bb'}
{ccc}{I got `ccc'}}%
[I got unknown string]\par}
\test{a} % I got `a'
\test{bb} % I got `bb'
\test{ccc} % I got `ccc'
\test{other} % I got unknown string
\end{document}
此外,对于字母表来说,它很难推广\@ifnextchar
。TeX 无法区分\foo
+ab
和单个命令\fooab
区分开来。
您可以定义多个以 开头的命令\foo
,但每个命令都应该以字母结尾。
\documentclass{article}
\begin{document}
\makeatletter
\def\strlist{a,bb,ccc}
\@for\curstr:=\strlist\do{%
\long\expandafter\edef \csname test\curstr\endcsname
{I got `\curstr'.\par}%
}
\makeatother
\testa % I got `a'
\testbb % I got `bb'
\testccc % I got `ccc'
\end{document}
使用etextools
,你可以部分推广\@ifnextchar
到多个字符(允许非字母或字母)。这是最接近的一个。
\documentclass{article}
\usepackage{etextools}
\usepackage{xstring}
\begin{document}
\def\test{%
\futuredef[-+ab]\nexttokens{%
\IfStrEqCase{\nexttokens}{%
{-}{I got `-'}
{-+}{I got `-+'}
{+ab}{I got `+ab'}}%
[I got unknown string]\par}}
\test- % I got `-'
\test-+ % I got `-+'
\test+ab % I got `+ab'
\test++ab % I got unknown string
\test a % I got unknown string
\end{document}
答案3
这是 Joseph Wright 解决方案的变体。\ifstrcmpTF
比较字符串,而不考虑它们的 catcode。
\makeatletter
\usepackage{catoptions}
\newcommand\@ifnextchars[3]{%
\def\@tempa{#1}\def\@tempb{#2}%
\def\@tempc{#3}\def\@tempd{}%
\@ifnextchars@a
}
\def\@ifnextchars@a#1{%
\toks@\cptthreexp{\expandafter\@car\@tempa\@nil}%
\expandafter\ifstrcmpTF\expandafter{\the\toks@}{#1}{%
\edef\@tempd{\expandcsonce\@tempd\the\toks@}%
\toks@\cptthreexp{\expandafter\@cdr\@tempa\@nil}%
\edef\@tempa{\the\toks@}%
\ifcsemptyTF\@tempa{\expandafter\@tempb\@tempd}%
\@ifnextchars@a
}{%
\edef\@tempd{\expandcsonce\@tempd#1}%
\expandafter\@tempc\@tempd
}%
}
\begin{document}
% Tests
\@ifnextchars{abc}{yes}{no} abc
\@ifnextchars{abc}{yes}{no} acb
\@ifnextchars{abc}{yes}{no} cba
\end{document}
Chervet Florent提出了一种可扩展的形式\@ifnextchar,
。我们能否想到一种可扩展的形式\@ifnextchars?
答案4
我做了一点小技巧,将一个嵌入\ifnextchar
另一个\ifnextchar
。当这个成功时,我将另一个嵌入第二个中,所以现在它考虑了三个字符。我的目标是排版一个希腊字母,并在其周围留出额外的空格,除非下一个字符是逗号、句号或破折号。
这是代码。
\makeatletter
\newcommand{\singlegreekletter}[1]{%
\hspace{1mm}{\begin{greek}{#1}\end{greek}\hspace{1mm}}%
% three nested ifnextchar commands
\@ifnextchar{.}{\nolinebreak\hspace{-.1em}}%
{\@ifnextchar{,}{\nolinebreak\hspace{-.1em}}%
{\@ifnextchar{-}{\nolinebreak\hspace{-.1em}}{ }}}% keep space
}%
\makeatother