Пользовательское определение \ref вызывает проблему внутри аргумента \caption

Пользовательское определение \ref вызывает проблему внутри аргумента \caption

Я пытаюсь реализовать пользовательскую версию команды \ref. Я обнаружил, что для того, чтобы я мог переопределить эту команду, мне нужно сделать это через \AtBeginDocumentas, иначе мои изменения, похоже, будут перезаписаны чем-то другим.

Теперь он работает так, как и ожидалось, за исключением случая использования \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}%
  }%
}%

может сделать его более читабельным, поскольку уровни более очевидны.

Связанный контент