3

Given a LaTeX document, I'd like to use an automatic method to know which one of all the labels is the most referenced one, which one is the second most referenced one and so on. I'll give you an example to make it clear. Suppose we have this document:

\documentclass{article}

\usepackage{amsthm}

\theoremstyle{plain}
\newtheorem{theorem}{Theorem}
\newtheorem{lemma}{Lemma}

\begin{document}
 \begin{lemma}
  \label{lm:1} Content of the first lemma.
 \end{lemma}
 Using lemma~\ref{lm:1} we have the following:
 \begin{lemma}
  \label{lm:2} Content of the second lemma.
 \end{lemma}
 Another consequence of lemma~\ref{lm:3} is the following:
 \begin{lemma}
  \label{lm:3} Content of the third lemma.
 \end{lemma}
 Finally, combining lemmas~\ref{lm:1},~\ref{lm:2},~\ref{lm:3} we have the following:
 \begin{theorem}
  \label{th:1}
 \end{theorem}
\end{document}

In this case, the list I'd like to see is the following one:

  1. lm:1

  2. lm:3

  3. lm:2

  4. th:1

Since lm:1 and lm:2 are both referenced twice, another acceptable list is the following one:

  1. lm:3

  2. lm:1

  3. lm:2

  4. th:1

I don't need every possible list, one of them is enough.

Edit: what if, in the process of making such a list, we want to ignore every label starting with a specific prefix? Suppose we want to ignore every label starting with "lm" in the previous example. Then the desired output would be the following:

  1. th:1
2

Here is a way:

\documentclass{article}

\usepackage{amsthm}
\usepackage{pgffor}
\theoremstyle{plain}
\newtheorem{theorem}{Theorem}
\newtheorem{lemma}{Lemma}

\let\oldref\ref
\let\oldlabel\label
\newcounter{labls}
\makeatletter
\def\ref#1{%
\@ifundefined{refrs@#1}{\xdef\temp{1}\expandafter\expandafter\expandafter\global\expandafter\let\csname refrs@#1\endcsname\temp}{%
\xdef\temp{\expandafter\expandafter\expandafter\number\expandafter\numexpr\csname refrs@#1\endcsname+1\relax}\expandafter\expandafter\expandafter\global\expandafter\let\csname refrs@#1\endcsname\temp\oldref{#1}}%
}

\def\label#1{%
\@ifundefined{labls@#1}
{\stepcounter{labls}}%
{Error:Already Defined Label: #1}
\@ifundefined{refrs@#1}{\xdef\temp{0}\expandafter\expandafter\expandafter\global\expandafter\let\csname refrs@#1\endcsname\temp}{\relax}%
\xdef\temp{#1}%
\expandafter\expandafter\expandafter\global\expandafter\let\csname LabelName\arabic{labls}\endcsname\temp\oldlabel{#1}%
}
\makeatother



\newcommand\reflist[1][]{%
\foreach\i in {1,...,\value{labls}}{%
\expandafter\expandafter\expandafter\global\expandafter\let\csname printed\i\endcsname\undefined%
}%
\foreach\k in {1,...,\value{labls}}{%
\xdef\maxRefs{-1}%
\xdef\printLabelNum{\k}%
\xdef\printLabelName{\csname LabelName\k\endcsname}%
\foreach \l in {1,...,\value{labls}}{%
\xdef\CurLabel{\csname LabelName\l\endcsname}%
\xdef\CurNum{\l}%
\xdef\CurRefs{\csname refrs@\CurLabel\endcsname}%
\ifnum\CurRefs > \maxRefs
\ifcsname printed\l\endcsname
\relax
\else
\xdef\maxRefs{\CurRefs}%
\xdef\printNum{\l}%
\fi
\fi
}%
{\bfseries \k)\csname LabelName\printNum\endcsname\xdef\t{#1}\ifx\t\empty\relax\else:~\maxRefs\fi\ifnum\k<\value{labls}\\\fi}%
\expandafter\expandafter\expandafter\global\expandafter\let\csname printed\printNum\endcsname\maxRefs%
}%
}

\begin{document}
 \begin{lemma}
  \label{lm:1} Content of the first lemma.
 \end{lemma}
 Using lemma~\ref{lm:1} we have the following:
 \begin{lemma}
  \label{lm:2} Content of the second lemma.
 \end{lemma}
 Another consequence of lemma~\ref{lm:3} is the following:
 \begin{lemma}
  \label{lm:3} Content of the third lemma.
 \end{lemma}

 Finally, combining lemmas~\ref{lm:1},~\ref{lm:2},~\ref{lm:3} we have the following:
 \begin{theorem}
  \label{th:1}
 \end{theorem}

\noindent\reflist\vspace{1cm}

%You may add a non empty optional argument to print the appearances
\noindent\reflist[ ]

\end{document}

enter image description here

0

For this kind of application I often find it easier to use an scripting language that parses the text file. Here is an example with unix tools, where your file is named doc.tex

   sed "s:\}:\}\n:g" doc.tex |\
   sed -rn "s:.*ref\{(.*)\}.*:\1:p" |\
   sort | uniq --count

This outputs

      2 lm:1
      1 lm:2
      2 lm:3

Which you can then sort by piping it to sort -r

The first sed command inserts newline after }, the following command matches the \ref{} pattern, but only once per line, thus why the previous command is used. The subsequent commands are self explanatory.

To ignore labels you can either make the regex more specific, or filter the output above

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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