介绍:
当您\renewcommand
在另一个宏或环境中使用时,需要将 加倍才能##
访问内部宏的参数。这可以作为区分内部宏##1
和外部宏的一种方式#1
(即使外部宏没有任何参数,它也提供错误检查)。例如:
\newcommand*{\OuterCommand}{%
\renewcommand*{\SomeCommand}[1]{\color{red}##1}%
....
}%
下面的参考资料提供了有关此内容的更多详细信息。
问题:
#
看起来,在循环内需要进行相同的加倍,\foreach
如下面的 MWE 所示。
我花了很长时间才弄清楚,因为下面的 MWE 给出的错误消息是:
\pgffor@body 定义中的参数编号非法
这是一个非常深的循环嵌套\foreach
,所以我确信问题出在我嵌套得\foreach
太深了。令人惊讶的是,如果你跳过错误,输出仍然是正确的,所以这让定位问题变得更加困难。
问题:
- 既然
\foreach
没有像 这样的参数#1
(就像\newcommand
有 一样),为什么需要#
在 内的定义中将加倍\foreach
? - 如果您只是忽略错误并按回车键继续处理,那么输出怎么仍然正确呢?
参考:
代码:
\documentclass{article}
\usepackage{xcolor}
\usepackage{pgffor}
\newcommand*{\MyList}{A,B,C}%
\newcommand{\SomeCommand}[1]{#1}%
\begin{document}
\foreach \x in \MyList {%
\renewcommand*{\SomeCommand}[1]{\color{red}#1}% Using ## here eliminates the error.
\par\SomeCommand{\x}%
}%
\end{document}
答案1
在内部,foreach 的定义将把循环主体保存在宏中,因此就像(如果循环a,b,...
)
\def\body{%
\renewcommand*{\SomeCommand}[1]{\color{red}#1}% Using ## here eliminates the error.
\par\SomeCommand{\x}%
}%
}
\def\x{a}\body
\def\x{b}\body
...
初始\def
(或者\newcommand
如果您愿意)将要求#
在正文中输入。如上所示,您会在不接受参数的情况##
下收到错误,您必须输入 ,正如您所发现的。#1
\body
##1
可以以不需要这样做的方式定义循环(例如,它可以使用令牌寄存器而不是宏来保存主体)但这显然不是这里的情况。
请注意,需要加倍#
与存在内部宏定义无关。这并不是说内部宏需要##1
引用第一个参数,而只是内部宏定义需要两个标记#
和1
来引用第一个参数,并将 放入#
宏主体中,您需要##
。要了解这一点,请考虑没有 的定义##1
。
你可以走了
\let\hash=#
并将\hash
被允许,#
但你不能将宏定义为
\def\definehash{\let\hash=#}
因为会产生
! Illegal parameter number in definition of \definehash.
您需要在宏定义中##
引用文字#
。因此需要
\def\definehash{\let\hash=##}
您在评论中询问为什么双重嵌套定义需要四个#
。同样,内部定义也没有什么特别之处,它们##1
在评估时永远不会“看到”,它们只会看到一个#
。如果您尝试定义
\def\ddefinehash{\def\definehash{\let\hash=##}}
定义将会顺利进行,但是如果你尝试执行,\ddefinehash
你会发现它只有一个单身的 #
在其定义中,因此您会像以前一样收到错误:
! Illegal parameter number in definition of \definehash.
<to be read again>
}
l.12 \ddefinehash
所以你需要二 #
进入定义\definehash
,并且每个都必须输入,所以##
你最终会得到
\def\ddefinehash{\def\definehash{\let\hash=####}}
综合起来:
{
\let\hash=#
}
{
\def\definehash{\let\hash=##}
}
{
\def\ddefinehash{\def\definehash{\let\hash=####}}
\ddefinehash
\definehash
\show\ddefinehash
\show\definehash
\show\hash
}
\bye
> \ddefinehash=macro:
->\def \definehash {\let \hash =####}.
l.15 \show\ddefinehash
?
> \definehash=macro:
->\let \hash =##.
l.16 \show\definehash
?
> \hash=macro parameter character #.
l.17 \show\hash
?
)
No pages of output.