\ nameref usando texto 'não expandido'?

Nov 03 2020

Suponha que eu defina um comando personalizado da \exerciseseguinte maneira.

\newcounter{exercise}
\newcommand\exercise{%
    \refstepcounter{exercise}%
    \section*{Exercise \theexercise}%
}

Agora, no exemplo a seguir, quero usar \namerefdo hyperrefpacote.

\exercise\label{ex:first}
foo

\exercise\label{ex:second}
see \nameref{ex:first}

\exercise\label{ex:third}
bar

Isso produz "consulte o Exercício 2" em vez de "consulte o Exercício 1". Parece que o texto 'não expandido' é usado, expandindo para o valor do contador atual. Como posso ter certeza de que \nameref{ex:first}produz o "Exercício 1"?

(Claro, eu poderia apenas usar Exercise~\ref{ex:first}, mas isso é mais sujeito a erros. E, no futuro, posso querer substituir "exercício" por "problema" sem ter que localizar e substituir todas as ocorrências em meu documento.)


Exemplo completo:

\documentclass{article}

\usepackage{hyperref}

\newcounter{exercise}
\newcommand\exercise{%
    \refstepcounter{exercise}%
    \section*{Exercise \theexercise}%
}

\begin{document}

\exercise\label{ex:first}
foo

\exercise\label{ex:second}
see \nameref{ex:first}

\exercise\label{ex:third}
bar

\end{document}

Respostas

1 egreg Nov 03 2020 at 16:08

Na verdade, você precisa passar a expansão de \theexercise, porque hyperrefnão faz isso para o título.

\documentclass{article}
\usepackage{hyperref}

\newcounter{exercise}
\newcommand\exercise{%
  \par % just in case
  \refstepcounter{exercise}%
  \begingroup\edef\x{\endgroup
    \noexpand\section*{\unexpanded{Exercise} \theexercise}%
  }\x
}

\begin{document}

\exercise\label{ex:first}
foo

\exercise\label{ex:second}
see \nameref{ex:first}

\exercise\label{ex:third}
bar

\end{document}

Este é o conteúdo (resumido) do .auxarquivo:

\newlabel{ex:first}{{1}{1}{Exercise 1}{section*.1}{}}
\newlabel{ex:second}{{2}{1}{Exercise 2}{section*.2}{}}
\newlabel{ex:third}{{3}{1}{Exercise 3}{section*.3}{}}

Era

\newlabel{ex:first}{{1}{1}{Exercise \theexercise }{section*.1}{}}
\newlabel{ex:second}{{2}{1}{Exercise \theexercise }{section*.2}{}}
\newlabel{ex:third}{{3}{1}{Exercise \theexercise }{section*.3}{}}

com o seu código.

Nota. Porque \unexpanded{Exercise}? No caso particular é obviamente desnecessário, mas seria para o alemão “Übung”.


Você pode usar em seu clevereflugar.

\documentclass{article}
\usepackage{hyperref}
\usepackage[nameinlink]{cleveref}

\newcounter{exercise}
\newcommand\exercise{%
  \par % just in case
  \refstepcounter{exercise}%
  \section*{Exercise \theexercise}
}
\crefname{exercise}{Exercise}{Exercises}

\begin{document}

\exercise\label{ex:first}
foo

\exercise\label{ex:second}
see \cref{ex:first}

\exercise\label{ex:third}
bar

\end{document}

A saída é a mesma em ambos os casos.

Podemos evitar o \edef\x{\endgrouptruque? Sim, claro.

\documentclass{article}
%\usepackage{xparse} % not needed for LaTeX 2020-10-01 or later
\usepackage{hyperref}
\usepackage[nameinlink]{cleveref}

\ExplSyntaxOn
\NewDocumentCommand{\exercise}{}
 {
  \gooz_exercise:ne { \exercisename } { \theexercise }
 }
\cs_new_protected:Nn \gooz_exercise:nn
 {
  \par % just in case
  \refstepcounter{exercise}
  \section*{#1~#2}
 }
\cs_generate_variant:Nn \gooz_exercise:nn { ne }
\ExplSyntaxOff

\newcommand{\exercisename}{Exercise}
\newcounter{exercise}
\crefname{exercise}{\exercisename}{\exercisename s}

\begin{document}

\exercise\label{ex:first}
foo

\exercise\label{ex:second}
see \cref{ex:first} or \nameref{ex:first}

\exercise\label{ex:third}
bar

\end{document}

Observe que cleverefnão é necessário, apenas remova as chamadas relevantes se preferir \nameref.