Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

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

share|improve this question
    
@RyanReich Your code is cited here. –  Steven B. Segletes Mar 13 '13 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 –  Steven B. Segletes Mar 13 '13 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 '13 at 18:32
add comment

1 Answer

up vote 1 down vote accepted

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}
share|improve this answer
    
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 '13 at 18:42
    
That's a good point. –  Steven B. Segletes Mar 13 '13 at 18:44
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.