修补宏内的参数

修补宏内的参数

考虑以下使用补丁的示例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*一次性更改所有外观。

相关内容