我的\john
命令定义如下:
\def\john{\DontExpandMe}
我现在想反复改变它的定义,不断在前面添加一些额外的东西。
\foreach\i in {ape,bat,cow,dog} {
\xdef\john{\i,\unexpanded{\john}}
\show\john
}
我的意图是\show\john
每次迭代的命令都应该导致:
\john=macro: -> \DontExpandMe.
\john=macro: -> ape,\DontExpandMe.
\john=macro: -> bat,ape,\DontExpandMe.
\john=macro: -> cow,bat,ape,\DontExpandMe.
\john=macro: -> dog,cow,bat,ape,\DontExpandMe.
也就是说,我希望\john
在某种意义上“部分扩展”。但我无法做到这一点。我尝试了以下方法
- 如果我使用
\xdef
,那么整个命令就会扩展,包括\DontExpandMe
部分。 - 如果我仅使用
\gdef
,则\i
不会扩展。 - 如果我使用
\xdef
with\unexpanded{...}
around\john
(就像我在当前代码中所做的那样)那么我就会得到\john=macro: -> ape,\john.
and\john=macro: -> bat,\john.
等等。
这是我的代码。
\documentclass{article}
\usepackage{pgffor}
\begin{document}
\def\john{\DontExpandMe}
\show\john
\foreach\i in {ape,bat,cow,dog} {
\xdef\john{\i,\unexpanded{\john}}
\show\john
}
\end{document}
答案1
有问题的行是:
\xdef\john{\i,\unexpanded{\john}}
\i
应扩展(全部/一次?)并且\john
应扩展一次
\xdef
用和进行部分展开\unexpanded
:
在\unexpanded
读取左花括号之前,它处于扩展模式以吞噬空格。因此它可以用来潜入\expandafter
:
\xdef\john{\i,\unexpanded\expandafter{\john}}
(如果没有这个技巧,二 \expandafter
需要:
\xdef\john{\i,\expandafter\unexpanded\expandafter{\john}}
不使用 e-TeX 也可以通过使用令牌寄存器来实现相同的效果:
\toks0=\expandafter{\john}% similar trick as above to minimize the number of \expandafter
\xdef\john{\i,\the\toks0}
令牌寄存器的内容不再内部扩展\edef
。
\i
对和进行一个扩展步骤\john
:
与上面相同,但对于
\i
也是如此:\xdef\john{\unexpanded\expandafter{\i},\unexpanded\expandafter{\john}}
\expandafter
狂欢\gdef
:\expandafter\expandafter\expandafter\gdef \expandafter\expandafter\expandafter\john \expandafter\expandafter\expandafter{% \expandafter\i\expandafter,\john }
首先
\john
展开一次,然后\i
。
答案2
有很多方法可以做到这一点;最简单但风险较大的是使用\xdef
:
\def\john{\DontExpandMe}
\show\john
\foreach\i in {ape,bat,cow,dog} {%
\xdef\john{\i,\unexpanded\expandafter{\john}}%
\show\john
}
为什么风险更大?尝试使用\textbf{ape}
列表中的命令来查看效果:无法存活的命令\edef
将使代码严重死亡。更好的选择是\i
仅扩展一次:
\xdef\john{\unexpanded\expandafter{\i},\unexpanded\expandafter{\john}}%
使用令牌寄存器可能是一种选择:
\def\john{\DontExpandMe}
\show\john
\foreach\i in {ape,bat,cow,dog} {%
\toks0=\expandafter{\i}%
\toks2=\expandafter{\john}%
\xdef\john{\the\toks0,\the\toks2}%
\show\john
}
交付的令牌不会在或\the<token registers>
中进行进一步扩展。\edef
\xdef
LaTeX3语言中的宏:
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\prependreverselist}{mm}
{% #1 is the macro to extend; #2 is the list
\clist_map_inline:nn { #2 }
{
\tl_put_left:Nn #1 { ##1 , }
}
}
\ExplSyntaxOff
\newcommand{\john}{\DontExpandMe}
\prependreverselist{\john}{ape,bat,cow,dog}
\show\john
答案3
在 TeX 级别,这至少可以通过几种方式实现,具体取决于我们是否假设 e-TeX 可用。经典方式(没有 e-TeX)是使用标记寄存器进行定义:
\long\def\addtoclist#1#2{%
\begingroup
\toks@\expandafter{#1}%
\toks2{#2}%
\edef#1{\the\toks2,\the\toks@}%
\expandafter\endgroup
\expandafter\def\expandafter#1\expandafter{#1}%
}
我一直很谨慎,并假设新材料(#2
)根本不应该扩展。上面的工作方式是 TeX 仅在 内部扩展一次标记寄存器(“toks”)\edef
,因此我可以确保不会发生进一步的扩展。我使用了两个临时的 toks:(按名称\toks@
寻址\toks0
)和\toks2
(按数字寻址)。组意味着我不会影响其中已存储的任何值。
有了 e-TeX,我们不需要 group 或 toks 分配
\protected\long\def\addtoclist#1#2{%
\edef#1{\unexpanded{#2},\unexpanded\expandafter{#1}}%
}
其中\unexpanded
原始的行为类似于toks:您可以\expandafter
在之前使用来扩展要分配的材料{
。
(在这两种情况下,您确实需要检查是否为空的初始定义,但这不是这里的关键点。)
答案4
在...的帮助下cgnieder 的评论,我已修复我的代码如下:
\documentclass{article}
\usepackage{pgffor}
\usepackage{etoolbox}
\begin{document}
\def\john{\DontExpandMe}
\show\john
\foreach\i in {ape,bat,cow,dog} {
\xdef\john{\i,\expandonce{\john}}
\show\john
}
\end{document}
并在cgnieder 的其他评论,我已将代码缩短如下:
\documentclass{article}
\usepackage{pgffor}
\begin{document}
\def\john{\DontExpandMe}
\show\john
\foreach\i in {ape,bat,cow,dog} {
\xdef\john{\i,\unexpanded\expandafter{\john}}
\show\john
}
\end{document}