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

の新しい 6 つのインスタンスを見つけることができますか%?


補遺: @AlanMunn がコメントで指摘したように、パッケージをロードして に置き換える\protect場合、ディレクティブは必要ありません。etoolbox\renewcommand{\ref}...\renewrobustcmd{\ref}...

コードのフォーマット

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

レベルがより明確になるため、読みやすくなる可能性があります。

関連情報