
給定一份 LaTeX 文檔,我想使用一種自動方法來知道所有標籤中哪一個是被引用最多的標籤,哪一個是第二多被引用的標籤,依此類推。我給你舉個例子讓你明白。假設我們有這個文檔:
\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}
在這種情況下,我希望看到的清單如下:
流明:1
流明:3
流明:2
次:1
由於 lm:1 和 lm:2 都被引用兩次,另一個可接受的清單如下:
流明:3
流明:1
流明:2
次:1
我不需要所有可能的清單,其中一個就足夠了。
編輯:如果在製作這樣的清單的過程中,我們想要忽略以特定前綴開頭的每個標籤怎麼辦?假設我們要忽略上一個範例中以「lm」開頭的每個標籤。那麼所需的輸出將如下所示:
- 次:1
答案1
這是一個方法:
\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}
答案2
對於這種類型的應用程序,我經常發現使用解析文字檔案的腳本語言更容易。這是一個 unix 工具的範例,其中您的檔案名為doc.tex
sed "s:\}:\}\n:g" doc.tex |\
sed -rn "s:.*ref\{(.*)\}.*:\1:p" |\
sort | uniq --count
這輸出
2 lm:1
1 lm:2
2 lm:3
然後你可以透過管道將其排序sort -r
第一個 sed 指令在 } 之後插入換行符,以下指令與 \ref{} 模式匹配,但每行只插入一次,因此使用前一個指令。後續命令是不言自明的。
要忽略標籤,您可以使正規表示式更具體,或過濾上面的輸出