I am trying to implement a custom version of the \ref
command. I found out that in order for me being able to redefine this command I need to do so via \AtBeginDocument
as otherwise my change seemed to get overwritten by something else.
It works now as expected except when using \ref
inside a \caption
which will produce the following error:
Argument of \@caption has an extra }. \caption{Test here \ref{sec:Section}}
Paragraph ended before \@caption was complete. \caption{Test here \ref{sec:Section}}
Here is a MWE reproducing the problem:
\documentclass{article}
\usepackage{xstring}
\AtBeginDocument{%
\let\refCopy\ref
\renewcommand{\ref}[1]{%
\IfBeginWith{#1}{eq:}{
(\refCopy{#1})
}{
\refCopy{#1}
}
}
}
\setcounter{errorcontextlines}{999}
\begin{document}
\section{Section}
\label{sec:Section}
\begin{figure}
\caption{Test here \ref{sec:Section}}
\end{figure}
\end{document}
If I remove my custom implementation of \ref
the document compiles just fine.
What is causing this problem and how can I avoid it?
답변1
Your (re)definition of \ref
makes it a so-called "fragile" command. This matters if \ref
is used in the argument of a "moving command" -- such as \caption
. You need to change
\caption{Test here \ref{sec:Section}}
to
\caption{Test here \protect\ref{sec:Section}}
Moreover, you need to make sure that no spurious whitespace is introduced before or after the cross-referencing call-out. I suggest you change
\renewcommand{\ref}[1]{%
\IfBeginWith{#1}{eq:}{
(\refCopy{#1})
}{
\refCopy{#1}
}
}
to
\renewcommand{\ref}[1]{%
\IfBeginWith{#1}{eq:}{%
(\refCopy{#1})%
}{%
\refCopy{#1}%
}%
}%
Can you spot the six new instances of %
?
Addendum: As @AlanMunn has pointed out in a comment, the \protect
directives aren't needed if one loads the etoolbox
package and replaces \renewcommand{\ref}...
with \renewrobustcmd{\ref}...
.
Formatting the code as
\renewcommand{\ref}[1]{%
\IfBeginWith{#1}{eq:}{%
(\refCopy{#1})%
}{%
\refCopy{#1}%
}%
}%
may make it more readable, as the levels are more evident.