我正在格式化一个包含许多章节的长文档。大多数章节包含一些通用部分(例如“简介”、“结果”......),其中大多数都已贴上相应的标签(例如\label{sec:intro}
)\label{sec:results}
。这对于逐章而言没有问题,但是当我将它们放在一起时,这意味着某些标签将使用多次(例如,可能有来自sec:intro
五个不同章节的五个标签。)
我可以使用这些标签而不重命名它们吗?LaTeX 是否足够智能,知道.tex
第 2 章文件中\ref{sec:intro}
引用的是当前章节中的“简介”部分。
如果不是,首选的解决方案是什么?重命名所有标签似乎很笨重且不可靠。
答案1
正如 David Carlisle 所说,重命名你的标签。这可以通过使用流编辑器轻松完成,sed
例如。
假设您有一个关于狮子的章节文件和一个关于斑马的章节文件;在这两个章节文件中,您都使用了您描述的标签约定,如下所示:
狮子.tex
\chapter{Lions}
\section{Intro}\label{sec:intro}
\section{Results}\label{sec:results}
Here's a reference to \ref{sec:intro} and \ref{sec:results}.
zerbras.tex
\chapter{Zebras}
\section{Intro}\label{sec:intro}
\section{Intro}\label{sec:intro}
\section{Results}\label{sec:results}
Here's a reference to \ref{sec:intro} and \ref{sec:results}.
您可以使用sed
搜索和替换每个文件中的\label
每个\ref
文件,以便所有标签和引用都得到适当的更改
sed -i 's/\\\(label\|ref\){\([^}]*\)/\\\1{lions:\2/g' lions.tex
sed -i 's/\\\(label\|ref\){\([^}]*\)/\\\1{zebras:\2/g' zebras.tex
现在你的文件看起来如下
lions.tex(新)
\chapter{Lions}
\section{Intro}\label{lions:sec:intro}
\section{Results}\label{lions:sec:results}
Here's a reference to \ref{lions:sec:intro} and \ref{lions:sec:results}.
zebras.tex(新)
\chapter{Zebras}
\section{Intro}\label{zebras:sec:intro}
\section{Intro}\label{zebras:sec:intro}
\section{Results}\label{zebras:sec:results}
Here's a reference to \ref{zebras:sec:intro} and \ref{zebras:sec:results}.
理解\\\(label\|ref\){\([^}]*\)/\\\1{lions:\2/g
我使用的基本语法是s/old/new/g
用“新”替换“旧”。g
标志表示全局执行此操作。让我们将上述表达式分解为几个部分:
\\\(label\|ref\)
匹配\label
或\ref
并将结果存储到内存中,稍后用作\1
。请注意,我们需要使用\
转义特殊字符{\([^}]*\)
匹配里面的东西{...}
,但这样做非贪婪方式。这个正则表达式不能贪婪,这一点非常重要;如果贪婪,那么在操作表达式时Here's a reference to \ref{sec:intro} and \ref{sec:results}
它将匹配sec:intro} 和 \ref{sec:results}
这并不是我们想要的!
\\\1{lions:\2
是替换文本,使用\1
和\2
作为已存储在内存中的匹配。
另外支持 cleveref
Cleveref 使用\cref
和\Cref
。
sed -i 's/\\\(label\|[Cc]\?ref\){\([^}]*\)/\\\1{lion:\2/g'
对目录中的所有文件运行此操作很有用,并且通过使用*.tex
文件参数可以轻松完成,您的 shell(bash
,等等)将扩展到所有文件。
答案2
手动本地化标签和引用可以使用某种前缀来完成,例如,sec:labelA
如评论中所建议的那样。但这意味着必须更新所有出现的\label
,\ref
并\pageref
使用这些前缀。
另一方面,使用 TeX 来自动化并不那么困难:
\documentclass{article}
\AtBeginDocument{%
\let\origref\ref
\let\origpageref\pageref
\let\origlabel\label
\newcommand\locallabels[1]{%
\renewcommand\label[1]{\origlabel{#1##1}}%
\renewcommand\ref[1]{\origref{#1##1}}%
\renewcommand\pageref[1]{\origpageref{#1##1}}%
}}
\begin{document}
\section{A}\label{foo}
test \ref{foo} on \pageref{foo}
\locallabels{sec1:}
\newpage
\section{B}\label{foo}
test \ref{foo} on \pageref{foo}
\locallabels{}
\newpage
test \ref{foo} on \pageref{foo}
\end{document}
基本上,这会保存这些命令的当前定义,然后在\locallabels
调用时重新定义它们,以添加作为参数给出的前缀\locallabels
。
笔记
- 定义应该放在 的最后面,
\begin{document}
以便在某些包修改命令时获取命令的最新定义。例如hypherref
,使用 重新定义时,\AtBeginDocument
我们必须执行相同的操作。 - 如果使用类似扩展,则
varioref
此类包的命令将需要相同的处理。如果amsmath
使用,则需要额外调整的命令称为\label@in@display
,请参阅将自定义 \locallabels 命令与自定义 \eqref 命令结合使用 - 当然,每次使用都
\locallabels
应该使用不同的前缀,除非希望两个区域共享标签,例如,\locallabels{}
在示例中,返回到不使用前缀,因此选择了 A 部分的引用。 - 如果需要
\locallabels
从外部引用范围内的标签,可以使用 来实现\origref{<prefix><label}
。
答案3
我写了一个脚本在我把论文装订成论文时,呃,我的意思是写论文时,sed 策略对我来说不太管用,因为我使用 cleveref 在同一命令中引用多个标签,例如\Cref{sec:experiments,sec:results}
。
使用示例:
python add_ref_suffix.py --suffix chp1 --files *.tex
效果:\Cref{sec:experiments,sec:results}
变为\Cref{sec:experiments:chp1,sec:results:chp1}
,标签也相应改变。 没有什么特别的\Cref{}
;以 结尾的任何东西ref
都会改变,所以它应该适用于\ref
、\href
、\cref
、\autoref
等。我选择添加后缀而不是添加前缀,因为我使用了一个可以自动完成引用的 sublime 插件,并且我更喜欢在自动完成时按引用类型进行索引。