乍一看
\NewDocumentCommand{\foo}{m}{#1}
和
\def\foo#1{#1}
应该相同,并且在大多数情况下它们实际上是相同的,但是当参数没有明确跟随时\foo
,通过定义的命令\NewDocumentCommand
会Missing {
出错,而使用则\def
不会
这个问题有点像是以下问题的后续问题:>{...} 列规范中的宏延迟扩展 ,所以我将举这个例子来说明问题。看看 MWE:
\documentclass{article}
\usepackage{array}
\def\test#1{
\newcommand{\temp}[1][default]{##1}
#1\temp
}
\begin{document}
\begin{tabular}{>{\test}l}
[one]1\\
1\\
1\\
1
\end{tabular}
\end{document}
这个工作得很好,但是一旦我\test
像这样定义
\NewDocumentCommand{\test}{m}{
\newcommand{\temp}[1][default]{##1}
#1\temp
}
错误不断出现。
我自己发现,如果你在列规范\expandafter
之前添加,它可以与定义一起使用\test
\NewDocumentCommand
\begin{tabular}{>{\expandafter\test}l}
[one]1\\
1\\
1\\
1
\end{tabular}
但我想补充一点,
\documentclass{article}
\usepackage{array}
\NewDocumentCommand{\test}{mm}{
\newcommand{\temp}[1][default]{##1}
#2#1\temp
}
\begin{document}
\begin{tabular}{>{\test{foo}}l}
[one]1\\
1\\
1\\
1
\end{tabular}
\end{document}
在这里我无法用 来解决问题\expandafter
。
所以我的问题是,它如何使工作与不抛出一堆或任何其他批量解决方案\NewDocumentCommand
时的工作相同。\def
\expandafter
答案1
正如我之前提到的,这正式属于“未定义行为”,使用collcell
包然后照常处理数据。但无论如何,这是一个答案。
你必须理解\halign
原始函数的工作原理以及 3 种括号技巧(TeXbook 附录 D,或了解牙套使用技巧/大括号技巧展示:}、\egroup、\iffalse{\fi} 等。)来理解这个答案。
首先,制作一个 MWE:
\documentclass{article}
\begin{document}
\ExplSyntaxOn
\protected\def\test {\group_align_safe_begin: \testb}
\protected\def\testb #1 {\group_align_safe_end: #1}
\halign{\test\ignorespaces# \cr
123 \cr}
\ExplSyntaxOff
\end{document}
这里发生了什么?
根据定义,宏\test
将执行以下操作......
- 扩张
\group_align_safe_begin:
- 抢夺
\ignorespaces
令牌 - 扩张
\group_align_safe_end:
问题出现的原因是,当它这样做的时候......
- 展开
\group_align_safe_begin:
→ 将主计数器增加 1 - 抓取
\ignorespaces
token → 运行到模板 u 部分的末尾。TeX 在对齐条目的末尾标记目标主计数器应为 1 - 展开
\group_align_safe_end:
→返回主计数器。太迟了。
当&
看到时,它会理所当然地抱怨当前主计数器值为 0,而它应该是 1 才能正确结束对齐条目。
这里的问题是主计数器的明确调整,这在大多数情况下显然是需要的。
(附注:在这个特定的 MWE 中,你可以避免#
用
\halign{\test\ignorespaces\empty# \cr
123 \cr}
但如果你想窥视条目本身则不适用)
(顺便说一句,\expandafter
你之前放的\test
实际上没有任何效果,因为它\ignorespaces
是不可扩展的;尽管如此,它还是让 TeX“看到”了\ignorespaces
标记,并且“接触”了该#
部分,从而将目标主计数器值设置为 0 而不是 1)
不过,你可以通过“撤消”效果来选择“退出”它(强烈不推荐):
\protected\def\test{\group_align_safe_end: \testa} % remember to protect this, because the start of an alignment entry is initially expanded to look for e.g. \omit
\NewDocumentCommand\testa{m}{\group_align_safe_begin: #1}
它在上面的例子中确实起作用\halign
。
不用说,你可以找到禁用对齐保护是有害的例子。
对于诸如保护之类的事情\peek_analysis_map_inline:n
显然是有用的(https://github.com/latex3/latex3/issues/1090),
对于诸如此类的事情clist_map_
,它有点用处,
但对于参数抓取,我不确定。(也许抓取&
可选参数内部的数据也算数。)
还有这个(虽然有点做作......无论如何谁需要以 \cr 作为输入......?)
\documentclass{article}
\begin{document}
\ExplSyntaxOn
% the following 4 lines are equivalent to the simple \protected\def below
%\protected\def\test{\group_align_safe_end: \testa} % remember to protect this, because the start of an alignment entry is initially expanded to look for e.g. \omit
%\NewDocumentCommand\testa{+m}{\group_align_safe_begin:
% #1
%}
\protected\def\test #1{#1}
\halign{# \cr
\test \cr}
\ExplSyntaxOff
\end{document}