21

Consider the following example of a patch using etoolbox and a dummy macro \abc:

enter image description here

\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}

If I want to maintain good programming practice, I'm encouraged to put \patchcmd in the document preamble (separating structure from content) and only trigger it with a different macro, say \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}

However, the above does not work since #1 and #2 inside \patchabc is assumed to reference its arguments while \patchabc has none. How can I write a macro that acts like a switch (and is cleaner in terms of the programming) that patches another macro's use of its own arguments?

2 Answers 2

17

If you add \tracingpatches to the preamble you find the answer in the 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

And indeed, changing the catcode of # to 12 is working:

\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}

enter image description here

10

You can use 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}

The search regular expression \cP.1 means "find any character of type parameter (that is, category code 6) followed by 1", the replace expression \cP\#2 means the same, but the character to substitute will be #, again with category code 6.

If you want to get rid of #1 changing it into #2 wherever it appears in the replacement text of \abc, use

\regexpatchcmd*{\abc}{\cP.1}{\cP\#2}{}{}

However, also an easier \xpatchcmd works:

\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}

Also here you can use \xpatchcmd* to change all appearances at once.

0

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .