我有一个可以运行的此宏的部分版本,没有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 的权衡,这个问题的答案似乎有两个方面:
- 不要这样做!(当然,这个问题中的例子不是一个可靠的用例,可以用其他方式做得更好。)部分目的是
xparse
帮助过渡到LaTeX3
,并且如果可以避免的话,它并不打算鼓励使用更多晦涩难懂的语法。 - 如果您确实想做类似这个问题的事情,您可以使用
\futuredef
frometextools
,如下所示:
\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 编译器中实现;这是一个很方便的包。)