概括 \@ifnextchar 以考虑多个字符。

概括 \@ifnextchar 以考虑多个字符。

我正在寻找一种巧妙的方法来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

相关内容