根据这段代码片段,我得出结论\newcommand
命令是通过扩展之前的字符串替换来工作的:
\newcommand{\double}[1]{#1#1}
\newcounter{dummy}
\thedummy \double{\stepcounter{dummy}} \thedummy
输出0 2
,表示\stepcounter
出现在 之后两次\double
。因此它在被扩展/执行之前被替换。
但是,以下代码:
\newcommand{\append}[1]{#1long}
\newcommand{\mypi}{3.1}
\newcommand{\mypilong}{3.14159}
\append{\mypi}{4159}
输出3.1long
而不是3.14159
(这是您期望从字符串替换中获得的),表示\mypi
在替换之前已经扩展。
我做错什么了?
答案1
TeX 没有“字符串”的概念。它只适用于代币。
的替换文本由一个“参数标记”组成,它将在调用时被实际参数替换,\append
后跟四个标记l
、o
和n
g
。
TeX 使用 token 进行工作,并且永远不会将它们“附加”到控制序列名称中:它将绝不将两个 token 融合在一起。因此,当你调用时,\append{\mypi}
你会得到
\mypi•l•o•n•g
(其中项目符号用于标记标记之间的边界)。接下来\mypi
被其定义替换,您将获得
3.1长
{4159}
接下来将读取该部分,最终输出为
3.1long4159
你的\double
也有点问题。我猜你使用的正确代码是
\newcommand{\double}[1]{#1#1}
因为\newcommand{\double}[1]{#1}{#1}
放错位置会产生错误#
。
是否可以定义\append
以便\append{\mypi}
扩展\mypilong
?是的,有多种方法。一种方法是
\newcommand{\gobblebackslash}[1]{}
\newcommand{\append}[1]{\csname\expandafter\gobblebackslash\string#1long\endcsname}
解释:
- 我们要从各个部分构建一个控制序列名称,所以
\csname...\endcsname
需要; - 我们可以用来
\string\mypi
获取宏名,但是会有反斜杠; - 因此,我们首先通过扩展去掉反斜杠
\string\mypi
,然后让它\gobblebackslash
完成吞噬一个标记的工作。
这是否与标记永远不会融合在一起的说法相矛盾?不。原语\csname
扩展为使用它找到的标记构建的单个符号标记,直到匹配\endcsname
。
笔记。上面的代码隐式地假设的值\escapechar
是通常的值。