La definición personalizada de \ref causa un problema dentro del argumento de \caption

La definición personalizada de \ref causa un problema dentro del argumento de \caption

Estoy intentando implementar una versión personalizada del \refcomando. Descubrí que para poder redefinir este comando necesito hacerlo a través de, \AtBeginDocumentde lo contrario mi cambio parece ser sobrescrito por otra cosa.

Ahora funciona como se esperaba, excepto cuando se usa \refdentro de a, \captionlo que producirá el siguiente 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}}

Aquí hay un MWE que reproduce el problema:

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

Si elimino mi implementación personalizada del \refdocumento, se compila bien.

¿Qué está causando este problema y cómo puedo evitarlo?

Respuesta1

Su (re)definición de \reflo convierte en un comando llamado "frágil". Esto es importante si \refse usa en el argumento de un "comando de movimiento", como por ejemplo \caption. Necesitas cambiar

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

a

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

Además, debe asegurarse de que no se introduzcan espacios en blanco falsos antes o después de la llamada de referencia cruzada. te sugiero que cambies

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

a

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

¿Puedes detectar las seis nuevas instancias de %?


Apéndice: Como @AlanMunn señaló en un comentario, las \protectdirectivas no son necesarias si se carga el etoolboxpaquete y se reemplaza \renewcommand{\ref}...con \renewrobustcmd{\ref}....

Formatear el código como

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

puede hacerlo más legible, ya que los niveles son más evidentes.

información relacionada