如何使用 xparser 创建一个奇数分隔的宏?

如何使用 xparser 创建一个奇数分隔的宏?

我有一个可以运行的此宏的部分版本,没有xparse,但我需要对其进行调整,但它变得太笨重了,所以我尝试使用它xparse。不可否认,这是一个牵强的宏,但我正在尝试了解它xparse的工作原理...假设我尝试排版对句子及其变体的引用,如下所示:

X1
X2*
X3**
X4'
X56''

在哪里:

  • 可能会有一定数量的星号(表示畸形变体),这些星号的数量是先验未知的
  • 可以有一定数量的素数(表示形式良好的变体),这些素数的数量也是未知的
  • 后面的数字可能不止一位。数字以空格、逗号、分号或其他标点符号结尾。例如,$(\X'3; \X**45)$
  • X可以是任意字母字符串。
  • 它最好在文本和数学模式下工作。

我想将它们输入为\X**3, 或\X'4。 (我选择先放置标点符号,因为这样更容易让 TeX 以这种方式解析内容……)假设我已经有一个内部宏来排版实际内容:

\newcommand\@X[2]{ % #1 is the decorations, #2 is the number ... 
   \mbox{\ifmmode\text{X#2#1}\else X#2#1\fi}
}

现在我尝试定义用户可见的宏。我的第一个想法是

\DeclareDocumentCommand\X{ s s t' t' m }{ stuff }

但:

  • 这只处理两个星号和两个素数
  • 实际上,即使只有这两个星号和素数,我似乎也无法使它工作 :( 它给了我关于缺少$符号的错误,但我之前使用的数学模式代码\@X是可以工作的……
  • m参数仅抓取第一位数字,而不是像我的旧版本那样抓取整个数字标记。

有没有办法使用它来编程xparse,或者这只是一个太奇怪的宏而无法尝试支持?

编辑添加:昨晚我让以下定义起作用了。它们仅适用于'和数字,但不使用xparse

\newcommand\X{\@ifnextchar'\@Xprime{\@X{}}}
\newcommand\@Xprime[1]{\@ifnextchar'{\def\temp{\@Xprime{#1{'}}}\ex\temp\@gobble}{\@Xdigit{#1}}}
\newcommand\@Xdigit[2]{%
  \@ifnextchar1{\def\temp{\@Xdigit{#1}{{#2}1}}\ex\temp\@gobble}{%
  \@ifnextchar2{\def\temp{\@Xdigit{#1}{{#2}2}}\ex\temp\@gobble}{%
  \@ifnextchar3{\def\temp{\@Xdigit{#1}{{#2}3}}\ex\temp\@gobble}{%
  \@ifnextchar4{\def\temp{\@Xdigit{#1}{{#2}4}}\ex\temp\@gobble}{%
  \@ifnextchar5{\def\temp{\@Xdigit{#1}{{#2}5}}\ex\temp\@gobble}{%
  \@ifnextchar6{\def\temp{\@Xdigit{#1}{{#2}6}}\ex\temp\@gobble}{%
  \@ifnextchar7{\def\temp{\@Xdigit{#1}{{#2}7}}\ex\temp\@gobble}{%
  \@ifnextchar8{\def\temp{\@Xdigit{#1}{{#2}8}}\ex\temp\@gobble}{%
  \@ifnextchar9{\def\temp{\@Xdigit{#1}{{#2}9}}\ex\temp\@gobble}{%
  \@ifnextchar0{\def\temp{\@Xdigit{#1}{{#2}0}}\ex\temp\@gobble}{%
    \@X{#1}{#2}\xspace}%
  }}}}}}}}}}

这个想法是\@Xprime将所有素数逐个收集起来,并将它们放在括号组中,以防止它们变成双引号,然后将它们累积到其参数中。然后,它将该字符串传递给\@Xdigit,它会收集所有数字(数字没有自己的 catcode,所以我想不出比这个更短的测试......)并将它们累积到其第二个参数中。(我并不打算将每个数字放在括号组中,但却不知道如何将数字附加到#2。)最后,一旦它同时获得了素数和数字,它就会调用\@X来对它们进行排版,然后使用它\xspace来恢复空间处理。

\@Xstar可以这么说,我无法找到一个等价的,因为\@ifnextchar*它似乎没有实现我的意思,而且我认为它\@ifstar只会吞噬命令后面的空格,而不是命令后面的参数。

已编辑 我已经找到了以下版本,它的行为正确,但仍然不使用xparse。它使用\futuredef来自etextools,并且比以前的版本更简洁、更易懂……我仍然很好奇这将如何与“xparse”一起工作。

\DeclareRobustCommand\X{\@ifstar\@Xstar\@Xnostar}
\newcommand\@Xstar{\futuredef[*]\@Xstars{\futuredef[1234567890]\@Xdigits{\@X{\@Xstars}{\@Xdigits}}}}
\newcommand\@Xnostar{\@ifnextchar'\@Xprime{\futuredef[1234567890]\@Xdigits{\@X{}{\@Xdigits}}}}
\newcommand\@Xprime{\futuredef[']\@Xprimes{\futuredef[1234567890]\@Xdigits{\@X{\@Xprimes}{\@Xdigits}}}}
\newcommand\@X[2]{\mbox{\ifmmode\text{X#2#1}\else X#2#1\fi}\xspace}

答案1

我不太清楚您到底在寻找什么。也许像这样的简单解析器?

\documentclass{article}
\usepackage[T1]{fontenc}
\makeatletter
\newcount\x@cnt
\def\addto@extra@arg#1{\expandafter\def\expandafter\extra@arg\expandafter{\extra@arg#1}\X@i}
\def\X{\let\extra@arg\@empty\afterassignment\X@i\x@cnt0}
\def\X@i{\futurelet\nxt@tok\X@ii}
\def\X@ii{%
    \ifx'\nxt@tok\expandafter\addto@extra@arg
    \else
        \ifx*\nxt@tok\expandafter\expandafter\expandafter\addto@extra@arg
        \else\printargs
        \fi
    \fi}
\def\printargs{I saw \string\X\ then \fbox{\number\x@cnt} and \fbox{\extra@arg}.}
\makeatother
\begin{document}
\X54**text

\X2*text

\X123''text

\X text% the integer is ``0''

\X4'text
\end{document}

答案2

经过一段时间的搁置,并经过@BrunoLeFloch 和@JosephWright 的权衡,这个问题的答案似乎有两个方面:

  1. 不要这样做!(当然,这个问题中的例子不是一个可靠的用例,可以用其他方式做得更好。)部分目的是xparse帮助过渡到LaTeX3,并且如果可以避免的话,它并不打算鼓励使用更多晦涩难懂的语法。
  2. 如果您确实想做类似这个问题的事情,您可以使用\futuredeffrom etextools,如下所示:

 

\DeclareRobustCommand\X{\@ifstar\@Xstar\@Xnostar}
\newcommand\@Xstar{\futuredef[*]\@Xstars{\futuredef[1234567890]\@Xdigits{\@X{\@Xstars}{\@Xdigits}}}}
\newcommand\@Xnostar{\@ifnextchar'\@Xprime{\futuredef[1234567890]\@Xdigits{\@X{}{\@Xdigits}}}}
\newcommand\@Xprime{\futuredef[']\@Xprimes{\futuredef[1234567890]\@Xdigits{\@X{\@Xprimes}{\@Xdigits}}}}
\newcommand\@X[2]{\mbox{\ifmmode\text{X#2#1}\else X#2#1\fi}\xspace}

怎么运行的:\futuredef[chars]\x\y将收集以下所有后续字符\y 只要它们是 [chars] 中的一个字符,将结果存储在 中\x,然后执行\y。在底层,\futuredef使用单字符\futurelet原语,\@ifstar和 也是如此\@ifnextchar,尽管它们工作方式的具体细节令人费解。

因此,在这个定义中,初始值\@ifstar在接受星号或素数之间进行选择,但不消耗任何字符。 \@Xstar使用\futuredef[*]\@Xstars将所有星号收集到中\@Xstars,然后继续使用大括号组,它使用\futuredef[1234567890]\@Xdigits将所有数字收集到中\@Xdigits,然后进行\@X相应的调用。 \@Xnostar使用\@ifnextchar'对素数执行与对星号相同的操作\@ifstar。最后,\@Xprime对素数执行与\@Xstar对星号相同的操作。

(总的来说,etextools有一些有趣、强大、低级的工具,我不知道这些工具可以在当前的 TeX 编译器中实现;这是一个很方便的包。)

相关内容