\ref 的自定义定义导致 \caption 参数内部出现问题

\ref 的自定义定义导致 \caption 参数内部出现问题

我正在尝试实现命令的自定义版本\ref。我发现,为了能够重新定义此命令,我需要通过 来执行此操作,\AtBeginDocument否则我的更改似乎会被其他内容覆盖。

它现在可以按预期工作,但\ref在内部使用时除外,\caption否则会产生以下错误:

Argument of \@caption has an extra }. \caption{Test here \ref{sec:Section}}
Paragraph ended before \@caption was complete. \caption{Test here \ref{sec:Section}}

以下是重现该问题的 MWE:

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

\ref如果我删除文档 的自定义实现,编译就正常了。

是什么原因导致了这个问题?我该如何避免它?

答案1

您对 的(重新)定义\ref使其成为所谓的“脆弱”命令。如果\ref被用于“移动命令”的参数中,例如,那么这一点很重要\caption。您需要更改

\caption{Test here \ref{sec:Section}}

\caption{Test here \protect\ref{sec:Section}}

此外,你需要确保在交叉引用调用之前或之后没有引入虚假的空格。我建议你改变

    \renewcommand{\ref}[1]{%
        \IfBeginWith{#1}{eq:}{
            (\refCopy{#1})
        }{
        \refCopy{#1}
    }
}

    \renewcommand{\ref}[1]{%
        \IfBeginWith{#1}{eq:}{%
            (\refCopy{#1})%
        }{%
        \refCopy{#1}%
    }%
}%

您能发现这六个新的实例%吗?


附录:正如@AlanMunn 在评论中指出的那样,如果加载包并用 替换,则不需要\protect这些指令。etoolbox\renewcommand{\ref}...\renewrobustcmd{\ref}...

将代码格式化为

\renewcommand{\ref}[1]{%
  \IfBeginWith{#1}{eq:}{%
    (\refCopy{#1})%
  }{%
    \refCopy{#1}%
  }%
}%

可能会使其更具可读性,因为级别更加明显。

相关内容