1

The question Back-referencing in LaTeX was marked a duplicate, so I can't post to that thread. Nonetheless, I found the code provided there by Ryan Reich to be a good learning exercise. His solution provided a comma-separated list of back references, without spaces.

I just thought that his approach would be even more useful, if it could be modified to produce not just a string of comma separated numbers, but actual legible text that might be used in a document.

So I tried to improve his solution

3
  • @RyanReich Your code is cited here. Mar 13, 2013 at 13:45
  • @lockstep I added back strings as a tag, because the method requires string manipulation (as embodied in \convertword) in order to remove redundant occurances of "and" from the constructed string Mar 13, 2013 at 18:12
  • So I am surprised to find. Though, note, that @ tags don't alert someone who isn't already part of the comment thread, so this is purely a coincidence.
    – Ryan Reich
    Mar 13, 2013 at 18:32

2 Answers 2

3

The cleveref-usedon package allows for easy back referencing that uses cleveref's formatting (E.g., "Theorem 1", "Section II").

To use it, I needed to install it as it didn't come as part of my LaTeX installation.

EDIT: As of August 2023, there is a bug in cleverf-usedon that causes some back-references to not appear. See this issue on GitHub.

1

So here is one solution:

\documentclass{article}
\usepackage{etoolbox}
\usepackage{stringstrings}

\makeatletter

\def\@newbackl@bel#1#2#3{%
 \@ifundefined{#1@#2}%
  {\global\@namedef{#1@#2}{#3}}
  {\cs@g@appendpair{#1@#2}{#3}}%
}
% #1 and #2 are each of the form {a}{b}, and the a and b groups are to be
% concatenated independently.
\def\cs@g@appendpair#1#2{{%
 \edef\first{\csname #1\endcsname}%
 \edef\firsta{\expandafter\@firstoftwo\first}%
 \convertword[q]{\firsta}{and}{}%
 \edef\firsta{\thestring}%
 \edef\firstb{\expandafter\@secondoftwo\first}%
 \convertword[q]{\firstb}{and}{}%
 \edef\firstb{\thestring}%
 \csxdef{#1}%
  {{\firsta, and \@firstoftwo#2}%
   {\firstb, and \@secondoftwo#2}}%
}}

% Patching into the existing commands
\def\newbacklabel{\@newbackl@bel B}
\let\backlabel=\label
\patchcmd\backlabel{\newlabel}{\newbacklabel}{}{}
\let\backref=\ref
\patchcmd\backref{r@#1}{B@#1}{}{}
\let\pagebackref=\pageref
\patchcmd\pagebackref{r@#1}{B@#1}{}{}
\pretocmd\ref{\backlabel{#1}}{}{}

\makeatother

\begin{document}
\begin{enumerate}
 \item \label{e:1} Part 1, referenced by part(s) \backref{e:1}
    on page(s) \pagebackref{e:1}.
 \item \label{e:x} Part 2, referenced by part(s) \backref{e:x} on
page(s) \pagebackref{e:x}, and referencing part \ref{e:1}.
 \item \label{e:2} Part 3, referencing part \ref{e:1} and \ref{e:x}
 \item \label{e:3} Part 4, referencing part \ref{e:1}.
\end{enumerate}
\newpage
\section{A section}
\label{s:1}
Here is another reference to part \ref{e:1}.

\end{document}

enter image description here

And for those frustrated with the slowness of the stringstrings package, here is a longer, but much faster alternative

\documentclass{article}
\usepackage{etoolbox}
\usepackage{stringstrings}

\makeatletter

\def\@newbackl@bel#1#2#3{%
 \@ifundefined{#1@#2}%
  {\global\@namedef{#1@#2}{#3}}
  {\cs@g@appendpair{#1@#2}{#3}}%
}
% #1 and #2 are each of the form {a}{b}, and the a and b groups are to be
% concatenated independently.
\def\cs@g@appendpair#1#2{{%
 \edef\first{\csname #1\endcsname}%
 \edef\firsta{\expandafter\@firstoftwo\first}%
 \replacewordF[q]{\firsta}{and}{}%
 \edef\firsta{\thestring}%
 \edef\firstb{\expandafter\@secondoftwo\first}%
 \replacewordF[q]{\firstb}{and}{}%
 \edef\firstb{\thestring}%
 \csxdef{#1}%
  {{\firsta, and \@firstoftwo#2}%
   {\firstb, and \@secondoftwo#2}}%
}}

% Patching into the existing commands
\def\newbacklabel{\@newbackl@bel B}
\let\backlabel=\label
\patchcmd\backlabel{\newlabel}{\newbacklabel}{}{}
\let\backref=\ref
\patchcmd\backref{r@#1}{B@#1}{}{}
\let\pagebackref=\pageref
\patchcmd\pagebackref{r@#1}{B@#1}{}{}
\pretocmd\ref{\backlabel{#1}}{}{}

\usepackage{ifnextok}
\usepackage{ifthen}

\def\string@end{$}
\def\converttilde{T}
\newcounter{arg@index}
\let\SaveHardspace~

\def\getargsF#1{%
  \if T\converttilde\def~{ }\fi%
  \protected@edef\the@string{#1}%
  \def\argi{}\setcounter{arg@index}{1}%
  \expandafter\parse@Block\the@string\string@end%
  \let~\SaveHardspace%
}

%ifthenelse needed when leading spaces end up as \argi
\def\parse@Block{\IfNextToken\string@end%
  {\edef\narg{\arabic{arg@index}}\@gobble}%
  {\IfNextToken\@sptoken{\addtocounter{arg@index}{1}%
   \ifthenelse{\equal{\argi}{}}{\addtocounter{arg@index}{-1}}{}%
   \expandafter\def\csname arg\roman{arg@index}\endcsname{}%
   \add@to{\parse@Block}}%
  {\add@to{\parse@Block}}}}

  \def\add@to#1#2{\if\@sptoken#2\else\expandafter\protected@edef%
                 \csname arg\roman{arg@index}\endcsname%
                {\csname arg\roman{arg@index}\endcsname#2}\fi#1}

\newcounter{word@count}

% Replaces a word of alphanumeric phrase with another
% Syntax: \replacewordF[mode]{orig_string}{word}{replacement}
% mode is v for verbose, q for quiet (saved in \thestring}
% word is one whole word; cannot contain spaces.
% replacement can be multiword
\newcommand\replacewordF[4][v]{%
  \getargsF{#2}%
  \edef\thestring{\argi}%
  \setcounter{word@count}{1}%
  \whiledo{\value{word@count} < \narg}{%
    \addtocounter{word@count}{1}%
    \ifthenelse{\equal{\csname arg\roman{word@count}\endcsname}{#3}}%
    {\edef\the@string{\thestring\@sptoken}\edef\thestring{\the@string#4}}%
    {\edef\the@string{\thestring\@sptoken}%
       \edef\thestring{\the@string\csname arg\roman{word@count}\endcsname}}%
  }%
  \if v#1\thestring\fi%
}

\makeatother

\begin{document}
\begin{enumerate}
 \item \label{e:1} Part 1, referenced by part(s) \backref{e:1}
    on page(s) \pagebackref{e:1}.
 \item \label{e:x} Part 2, referenced by part(s) \backref{e:x} on
page(s) \pagebackref{e:x}, and referencing part \ref{e:1}.
 \item \label{e:2} Part 3, referencing part \ref{e:1} and \ref{e:x}
 \item \label{e:3} Part 4, referencing part \ref{e:1}.
\end{enumerate}

\newpage
\section{A section}
\label{s:1}
Here is another reference to part \ref{e:1}.

\end{document}
2
  • I don't really have anything to add to this. I might suggest that, rather than building the spaces and the "and" directly into \backref, you write an independent macro/function that converts a general comma-separated list into one with these features. That is, a,b,c goes to a, b, and c. This separates the essential from the cosmetic.
    – Ryan Reich
    Mar 13, 2013 at 18:42
  • That's a good point. Mar 13, 2013 at 18:44

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .