考虑以下示例:我们有一个命令\mycmd
,在某些包中定义为:
\DeclareRobustCommand{\mycmd}{%
<original source code>
}
我们想要修补此命令,即在前置和附加代码的意义上。这些可能包含任何内容,包括\if
\else
包装原始代码的构造。直接的当然,这样做的方法是最初以这种方式定义命令。如果命令已经存在,我们可以先使用etoolbox
's删除它来修补它\undef
:
\undef{\mycmd}
\DeclareRobustCommand{\mycmd}{%
<pre code>
<original source code>
<post code>
}
我的问题:
看来etoolbox
的设施(\appto
、\apptocmd
等等)并非在所有情况下都能发挥作用。
有没有什么方法可以实现这种修补,而不必逐字复制粘贴原始源代码(但在所有情况下都具有 100%相同的行为)?
这是一个后续问题重新定义 \- 的安全方法仅适用于数学模式
答案1
简短的回答:没有“明确的方法”。
如何(以及是否可能)修补(或添加或附加)命令取决于它的定义方式(\def
、\newcommand
、\DeclareRobustCommand
、\NewDocumentCommand
)、是否接受参数、命令的内容是什么,以及什么您想要修补该命令。
无参数的宏:最简单的情况是命令不带参数。在这种情况下,宏(用expl3
术语来说)是一个“标记列表”,您可以展开宏并对其内容执行任何操作。该标记列表中的所有内容(不出所料)都是标记,因此您可以遍历它、查询其内容、随意添加和删除标记。在这种情况下,添加前缀和后缀很简单(请参阅\g@addto@macro
in的定义latex.ltx
),再次修补中间内容的难度取决于您要替换的内容。
带参数的宏:更棘手的情况是宏带有参数。在这种情况下,您不能简单地展开它,因为展开时它会尝试获取参数,而这里没有这些参数(如果您这样做,则会丢失定义中的宏参数,这可能是您不想要的)。
在这种情况下,您必须使用适当的修补命令(如etoolbox
's \patchcmd
)。修补过程包括将整个定义转换为字符串(使用\meaning
),将 与 分离<parameter text>
,<replacement text>
进行替换,然后重新扫描字符串并使用 重新进行定义\scantokens
,希望在此过程中不会出错(请参阅对此的解释这里)。
修补的问题在于\scantokens
部分,它假设一种单一的 catcode 机制,而根据宏的定义方式,情况并非如此。以 LaTeX 2ε 的\rem@pt
宏为例。如果你这样做,\meaning\rem@pt
你会得到\rem@pt=macro:#1.#2pt->#1\ifnum #2>\z@ .#2\fi
(假设你只想用 替换:这似乎很容易)。修补这个的问题在于,在 中,和是 catcode-12 标记,而中的和必须是 catcode-11,这样你才能真正进行定义。.
除非(这并非不可能,但你必须小心)否则将拒绝在这里做任何事情。有些情况下,这完全是不可能的(尝试在 01-10-2019 之前的 LaTeX 中将任何内容修补到 的定义中)。,
#1.#2pt
p
t
p
t
\rem@pt
\patchcmd
\patchcmd
\end
如何定义(以及可选参数):假设该宏具有良好的 catcode 机制,并且您可以使用 对其进行修补。\patchcmd
当您定义\newcommand\foo[1][]{a#1b}
实际的的定义\foo
不是在 中\foo
,而是在 中\\foo
(名称中有两个反斜杠),因此您必须修补后者。这种情况相当简单:加载xpatch
并使用\xpatchcmd
(或\xpretocmd
或\xapptocmd
)代替。xpatch
将为您思考并找出它需要修补\\foo
(并将使用)。如果命令是用 定义的,那么也不会有帮助(这些etoolbox
命令\patchcmd
xparse
xpatch
能进行修补,但他们无意这样做,因此xpatch
甚至不尝试支持这一点)。
您要修补的内容:您在问题中提到了不平衡的\if
... \fi
,但这实际上不是问题。不平衡的条件在其他条件中是有问题的,而在修补时则不是这种情况。这里的问题是不平衡的{
... }
,因为修补宏假设括号是平衡的。根据您想要执行的操作,您可以解决问题(查看这里这只是一个例子,但实际上这是根据具体情况而定的。
l3regex
救援:最接近“确定”的修补方法是使用l3regex
(和regexpatch
)。该regexpatch
包使用 LaTeX3 正则表达式引擎 ( l3regex
) 来匹配和替换在不同 catcode 设置下设置的标记,以便您可以修补更棘手的内容。使用将在 的定义中\regexpatchcmd\command{<search-regex>}{<replace-regex>}{<true code>}{<false code>}
查找 ,并将替换为。该包与 相同,负责处理强大的命令和带有可选参数的命令。看看<search-regex>
\command
<replace-regex>
xpatch
l3regex
和regexpatch
正则表达式和修补命令的语法文档。