# Extra space due to \patchcmd

It seems that \patchcmd from etoolbox adds three unwanted spaces, as shown below:

\documentclass{minimal}
\usepackage{etoolbox}
\begin{document}
\tracingall%                            3 spaces in log file
\def\test{1}]\patchcmd\test{1}{2}{}{}[% 3 spaces between brackets in output
\end{document}


How can I fix this?

• Issue a number of \unskips: \def\test{1}]\patchcmd\test{1}{2}{}{}\unskip\unskip\unskip[ – Werner Dec 30 '13 at 0:09

## 1 Answer

Two spaces come from calls of \scantokens, the third from an unprotected end-of-line in the code.

\documentclass{minimal}
\usepackage{etoolbox}

\makeatletter
% Add \ifhmode\unskip\fi
\protected\def\etb@ifscanable#1{%
\begingroup
\edef\etb@resrvda{%
\def\noexpand\etb@resrvda####1\detokenize{macro}:####2->####3&{%
####1\def\string\etb@resrvda####2{####3}}%
\edef\noexpand\etb@resrvda{\noexpand\etb@resrvda\meaning#1&}}%
\etb@resrvda
\makeatletter
\scantokens\expandafter{\etb@resrvda}%
%%% ADDITION
\ifhmode\unskip\fi
%%% END ADDITION
\expandafter\endgroup\ifx#1\etb@resrvda
\expandafter\@firstoftwo
\else
\expandafter\@secondoftwo
\fi}
\def\etb@patchcmd@scantoks#1{%
\edef\etb@resrvda{\endgroup
\unexpanded{\makeatletter\scantokens}{#1}%
\catcode\number\@=\the\catcode\@\relax}%
\etb@resrvda
%%% ADDITION
\ifhmode\unskip\fi
%%% END ADDITION
}
% Fix a missing %'
\protected\long\def\etb@ifpattern#1#2{%
\begingroup
\edef\etb@resrvda{%
\def\noexpand\etb@resrvda####1\detokenize{#2}####2&{%
\endgroup\noexpand\noexpand\noexpand\ifblank{####2}}%
\edef\noexpand\etb@resrvda{\noexpand\etb@resrvda
\expandafter\strip@prefix\meaning#1\detokenize{#2}&}%
\noexpand\etb@resrvda}% <---------- MISSING IN etoolbox.sty
\etb@resrvda\@secondoftwo\@firstoftwo}

\makeatother

\begin{document}
\def\test{1}]\patchcmd\test{1}{2}{}{}[% brackets for checking

][% for check
\end{document}


However, the best strategy is never using \patchcmd in horizontal mode.

The corresponding command \xpatchcmd from regexpatch is free from this problem.

A different patch could be adding \@empty at the end of the two \scantokens:

\protected\def\etb@ifscanable#1{%
\begingroup
\edef\etb@resrvda{%
\def\noexpand\etb@resrvda####1\detokenize{macro}:####2->####3&{%
####1\def\string\etb@resrvda####2{####3}}%
\edef\noexpand\etb@resrvda{\noexpand\etb@resrvda\meaning#1&}}%
\etb@resrvda
\makeatletter
\scantokens\expandafter{\etb@resrvda\@empty}% <---- ADDED
\expandafter\endgroup\ifx#1\etb@resrvda
\expandafter\@firstoftwo
\else
\expandafter\@secondoftwo
\fi}
\def\etb@patchcmd@scantoks#1{%
\edef\etb@resrvda{\endgroup
\unexpanded{\makeatletter\scantokens}{#1\noexpand\@empty}% <---- ADDED
\catcode\number\@=\the\catcode\@\relax}%
\etb@resrvda}


In the second case, \noexpand\@empty is needed, because we're inside an \edef. However this requires more testing than I'm inclined to do.

I'd have liked patching the two commands with \patchcmd itself, but they resist it.

• shouldn't you have patched etoolbox with patchcmd for a satisfying virtuous circle? – David Carlisle Dec 30 '13 at 1:31
• with \endlinechar set to -1 one avoids the spaces coming from \scantokens: \begingroup\endlinechar-1 \patchcmd\test{1}{2}{}{}\global\let\test\test\endgroup. There remains the space you identified in \etb@ifpattern. – user4686 Dec 30 '13 at 8:43
• Are you going to contact CTAN about this? The code has the awkward 'author-maintained' status, but presumably a way around that can be found to fix it. – Joseph Wright Dec 30 '13 at 9:13
• @JosephWright I'm inclined to avoid proposing the insertion of \ifhmode\unskip\fi. The missing % should be fixed. – egreg Dec 30 '13 at 10:17