\newcommand 究竟如何工作?

\newcommand 究竟如何工作?

根据这段代码片段,我得出结论\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后跟四个标记long

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是通常的值。

相关内容