考虑以下使用补丁的示例etoolbox
和一个虚拟宏\abc
:
\documentclass{article}
\usepackage{etoolbox}% http://ctan.org/pkg/etoolbox
\newcommand{\abc}[2]{#1\ #2}% Magic macro
\begin{document}
\abc{A}{B}
% \patchcmd{<cmd>}{<search>}{<replace>}{<success>}{<failure>}
\patchcmd{\abc}{#1}{#2}{}{}%
\abc{A}{B}
\end{document}
如果我想保持良好的编程习惯,我建议将其放入\patchcmd
文档序言中(将结构与内容分开),并且只用不同的宏来触发它,比如\patchabc
:
\documentclass{article}
\usepackage{etoolbox}% http://ctan.org/pkg/etoolbox
\newcommand{\abc}[2]{#1\ #2}% Magic macro
\newcommand{\patchabc}{%
% \patchcmd{<cmd>}{<search>}{<replace>}{<success>}{<failure>}
\patchcmd{\abc}{#1}{#2}{}{}%
}
\begin{document}
\abc{A}{B}
\patchabc% Patch \abc
\abc{A}{B}
\end{document}
但是,上面的代码不起作用,因为假定内部引用其参数,#1
而内部没有参数。我如何编写一个宏,使其像一个开关一样(并且从编程角度来说更清晰),以修补另一个宏对其自身参数的使用?#2
\patchabc
\patchabc
答案1
如果你补充\tracingpatches
一下序言,你会发现答案如下log
:
[debug] tracing \patchcmd on input line 14
[debug] analyzing '\abc'
[debug] ++ control sequence is defined
[debug] ++ control sequence is a macro
[debug] -- nested patching command and parameters in patch
[debug] -> the patching command seems to be nested in the
[debug] argument to some other command
[debug] -> the patch text seems to contain # characters
[debug] -> either avoid nesting or use # characters with
[debug] category code 12 in the patch text
[debug] -> simply doubling the # characters will not work
确实,将 catcode 更改为#
是12
有效的:
\documentclass{article}
\usepackage{etoolbox}% http://ctan.org/pkg/etoolbox
\tracingpatches
\newcommand{\abc}[2]{#1\ #2}% Magic macro
\catcode`\#=12
\newcommand{\patchabc}{%
% \patchcmd{<cmd>}{<search>}{<replace>}{<success>}{<failure>}
\patchcmd{\abc}{#1}{#2}{}{}%
}
\catcode`\#=6
\begin{document}
\abc{A}{B}
\patchabc% Patch \abc
\abc{A}{B}
\end{document}
答案2
您可以使用regexpatch
:
\documentclass{article}
\usepackage{regexpatch}
\newcommand{\abc}[2]{#1\ #2}% Magic macro
\newcommand{\patchabc}{%
\regexpatchcmd{\abc}{\cP.1}{\cP\#2}{}{}%
}
\begin{document}
\abc{A}{B}
\patchabc
\abc{A}{B}
\end{document}
搜索正则表达式的\cP.1
意思是“查找任何类型参数(即类别代码 6)的字符,后面跟着 1”,替换表达式的\cP\#2
意思相同,但要替换的字符将是#
,类别代码也是 6。
如果您不想将#1
其更改为 的#2
替换文本中出现的任何内容\abc
,请使用
\regexpatchcmd*{\abc}{\cP.1}{\cP\#2}{}{}
然而,还有一个更简单的\xpatchcmd
方法:
\documentclass{article}
\usepackage{regexpatch}
\newcommand{\abc}[2]{#1\ #2}% Magic macro
\newcommand{\patchabc}{%
\xpatchcmd{\abc}{##1}{##2}{}{}%
}
\begin{document}
\abc{A}{B}
\patchabc
\abc{A}{B}
\end{document}
您还可以在这里\xpatchcmd*
一次性更改所有外观。