LaTeX教程(015)-LaTeX文档结构(15)

LaTeX教程(015)- LaTeX \LaTeX LATEX文档结构(15)

2.4 管理引用

LaTeX \LaTeX LATEX有一些命令能够很容易的管理文档中的引用。它支持交叉引用(cross-references,文档内部对象的引用),文献引用(bibliographic,对外部文档的引用),以及对所选的文字或表达式的索引(indexing)。索引和文献引用我们在后面讲解,这里先讲交叉引用。

要使用交叉引用,你需要对一个结构上的对象指派一个"key"(一个字符串,由字母,数字和标点符号组成),用来指向那个对象的位置。

\label{key}
\ref{key}
\pageref{key}

\label命令用来为当前的"活动对象"指派一个key。\ref命令放置一个用来区分给定对象(如章节,公式或者图号等,具体是哪个对像,取决于放置\label的时候哪个对象是活动的)的字符串。\pageref命令将\label命令所在的页的页码输出在文档中。每一个\label所声明的key是唯一的,不可重复。一个有用的习惯是在key中放置一个能够区分对象类型的前缀,如sec,可以作为章节划分命令的keyfig可以作为图片的key,等等,我们做个演示:

\documentclass{article}
\usepackage[a5paper,margin=1.5in]{geometry}
\begin{document}
\section{A Section}
\label{sec:this} % 在一个section对象下面插入一个key,sec:this
A reference to this section looks
like this: ``see section~\ref{sec:this} % 将上面的section编号输出到此处
on page~\pageref{sec:this}''. % 将上面的section编号所在的页码输出到此处
\end{document}

编译:

在这里插入图片描述

注意,使用前缀的习惯是为了增加代码的可读性,字符串如何定义,都不能决定我们要引用的是哪个对象,只有\label放置的位置才能决定。

那么,如何才能将\label放置在正确的位置呢?对于划分命令,如\chapter\section等; 环境,如equationfiguretabletheorem,和列表环境enumerate的各个层级,以及脚注命令\footnote等,都会设置一个引用字符串,该字符串包含当前对象的编号,就像上句例子中的"1",它将放置于我们使用\ref命令的地方。这个字符串在一个对象的开始时生成,在结束时重置。也就是说,第一个section的引用字符串就是1,当前section结束时,就不再是1了。因此,我们要引用这些对象,就要将key声明在它们的作用区域内。

上述规则对tablefigure环境是例外,它们的索引字符串是由\caption命令定义的。这就允许一个环境中可以放置很多对\caption\label命令。因为编号是由\caption生成的,所以\label要跟在\caption命令的后面,否则就会生成错误的编号。如果\label放置\caption的前面,\label就会捕捉到前一个对象的索引字符串,典型的情况就是当前的章节单位对象。

那么,如果多个不同的对象的作用范围是相互嵌套的呢?这种情况下我们以当前\label所在的最小(最近)作用范围为准。例如,在一个section中放置一个subsection,那么在进入subsection之前放置的\label,会捕捉到section的索引字符串。在进入subsection之后放置的\label,会捕捉到subsection的索引字符串。如果在subsection中放置一个图片环境,那么在进入图片环境后,在\caption之前放置的\label同样会捕捉subsection的索引字符串,在\caption后的则会捕捉图片环境的索引字符串。直到图片环境结束,则又会回到subsection中。

然而,有些对象的作用范围可能会受到一些因素的干扰,我们作个演示:

\documentclass{article}
\usepackage[a5paper,margin=1in]{geometry}
\begin{document}
\section{A section}
\section{A section}
\section{A section}
\subsection{A subsection}\label{sec:before}
Text before is referenced as `\ref{sec:before}'.
\begin{figure}[ht]
\label{fig:in1} % 有问题的
\begin{center}
\fbox{\ldots{} figure body \ldots}
\caption{First caption}
\label{fig:in2} % 好的
\bigskip
\fbox{\ldots{} figure body \ldots}
\caption{Second caption}
\label{fig:in3} % 好的
\end{center}
\label{fig:in4}% 有问题的
\end{figure}
\label{sec:after} % 有问题的,除非你想要的是页码
\raggedright
The labels are: `before' (\ref{sec:before}),
`fig:in1' (\ref{fig:in1}) -- bad, `fig:in2' (\ref{fig:in2}),
`fig:in3' (\ref{fig:in3}), `fig:in4' (\ref{fig:in4}) -- bad
and `after' (\ref{sec:after}) -- probably bad!
\end{document}

编译:

在这里插入图片描述

只有fig:in2fig:in3处的\label捕捉到的索引字符是我们想要的,而fig:in4不是。可以看出,是center环境限制了\caption生成的索引字符的作用范围,于是我们捕捉到了subsection的索引字符。

注意,在浮动体中使用center环境并不是一个好的习惯,不仅仅是因为它会限制索引的范围,还因为它会在浮动体的顶部生成一段额外的间距。更好的方法是使用\centering来避免这两个问题。

每当声明一个\label{key} LaTeX \LaTeX LATEX就会记录当前的索引目录和当前的页码。如果一节(section)很长,跨很多个页,此时,如果我们使用\label将不同的key标记在这一节的不同的位置,那么它们捕捉到的节索引字符是相同的,但是页码可能不同。

特殊的标记

一个索引由\ref产生,默认情况下,它产生的数据和相对应的\label命令有关,通常是一个编号。通常所有额外的排版都必须由用户自己提供。例如,默认情况下(就像上一个例子那样),subsection3.1的索引字符串就是3.1,如果你想生成像"第(3.1)小节"这样的索引字符串,(在前面的例子中)可以编写代码第(\ref{fig:in1})小节。其他对象也是一样的。

amsmath(一个用来写数学公式的包)提供了一个\eqref用来生成公式的索引字符串,它会在公式的编号外面放置一对括号。如果想要在一个编号的前后自动添加一些我们想要的字符串,如equation,可以使用\labelformat命令。也可以使用cleveref包,该包我们在2.4.2会讲。

\labelformat{counter}{formatting-code}
\Ref{label}

labelformat命令有两个参数,第一个是我们要索引的对象的计数器,第二个是它的样式。第二个参数应当包含一个#1用来接收要排版的编号。

\labelformat有一个副作用(对中文用户不影响),对英文用户来说,我们通常希望一个句子的第一个单词的首字母是大写的,而\ref生成的索引字符串,除编号以外都是确定的,例如,我们用\labelformatsection的索引定制了一个section xx的样式,如果在一句话中,这个索引出现在一个句子的开头呢?此时我们希望这个用Section xx代替section xx。此时我们就可以使用\Ref,它将索引字符串中了第一个单词的首字母大写。我们用一个例子演示:

\documentclass{article}
\usepackage[a5paper,margin=1in]{geometry}
\usepackage[nospace]{varioref}
\labelformat{section}{section~#1}
\labelformat{equation}{equation~(#1)}
% ~生成一个空格,和普通的空格不同的是,它使LaTeX不在此处断行
\begin{document}
\section{An example}\label{sec}
\Ref{sec} shows the use of the \verb=\labelformat=
declaration with a reference to \ref{eq}.
\begin{equation}
    a = b \label{eq}
\end{equation}
\end{document}

编译:

在这里插入图片描述

要使\Ref正常工作,那么你定制的索引最好是以字母开头的,否则可能无法转换成大写,更糟糕的情况是可能会报错。当然,如果定制成中文则不需要使用\Ref了,也就不需要担心这个问题了。在一些语言中,字母还会带有重音符号,对这些情形也有一些调整措施,然而绝大多数的中文用户都不需要考虑这个问题,这里不再展开讲,确有需要的读者可以翻阅原著。

默认情形下,脚注(footnote)的索引字符串就是一个编号(默认是自然数,如1,2,3等),并且在reportbook的文档类中,每开始新的一章,脚注的编号也会重置。那么,如果我文档中看到一个footnote x的索引,我如何知道它指向的是当前章的第x个脚注还是其他的某章的第x个脚注呢?

我们可以在通过\labelformat设置,使得\label捕捉索引字符串的时候,将章的编号信息一并捕捉到,例如:

\documentclass{book}
\usepackage[a5paper,margin=1in]{geometry}
\labelformat{footnote}{footnote~(#1)in chapter~\thechapter}
\begin{document}
\chapter{chapter one}
some text \footnote{A Footnote\label{f:a}}
\chapter{chapter two}
some text\dots
\ref{f:a}
\end{document}

编译(只截取部分):

在这里插入图片描述

或者,我们也可以添加一个判断,实现如果引用的脚注在来自前章时,直接输出脚注编号,而如果来自其他章时,则将其所在章的编号信息一同输出出来:

\documentclass{book}
\usepackage[a5paper,margin=1in]{geometry}
\usepackage{ifthen,varioref}
\labelformat{footnote}{footnote #1\protect\iscurrentchapter{\thechapter}}
\newcommand\iscurrentchapter[1]{%
\ifthenelse{\equal{#1}{\thechapter}}{}{ in Chapter~#1}}
\begin{document}
\chapter{chapter one}
some text \footnote{A Footnote\label{f:a}} \ref{f:a}
\chapter{chapter two}
some text\dots
\ref{f:a}
\end{document}

编译:
在这里插入图片描述

在这里插入图片描述

ifthen包提供的\ifthenelse命令用来进行判断,这个例子中,我们用它判断\label捕捉到的\thechapter信息和当前的章的\thechapter是否一致。而varioref则是我们接下来要讲的包。

2.4.1 varioref-更灵活的交叉引用

很多时候,在引用图形或者表格环境时,将\ref或者\pageref都用上,是个很有用的习惯,因为,例如一个表格对象,可能跨很多页,我们最好不仅能定位到这个对像,也要知道我们要引用的部分在哪一页。

很多人可能会定义一个这样的命令:

\newcommand\fullref[1]{\ref{#1} on page~\pageref{#1}}

来将这两种引用合并到一个命令中。然是,我们在编写文档时,无法总是确定所引用的对象最终会落在哪一页(尤其是浮动体),所以可能会出现引用到当前页的情形。由Frank Mittelbach编写的varioref包试图自动解决这个问题。该包提供了命令\vref\vpageref来处理单个引用,也提供了命令\vrefrange\vpagerefrange来处理多个引用。

我们总是建议你在调用varioref的时候指定nospace包选项,如果不指定,varioref就会操作它的命令前面的空格(如果没有空格,它还会自己加上一个),这可能会导致一些问题,应当避免它。更多相关的细节后面会讲。

现在我们讲一下\vref\Vref及其星号变体的命令的形式。

\vref[same-page]{key}
\Vref[same-page]{key}
\vref*[same-page]{key}
\Vref*[same-page]{key}

当引用(\ref)和被引用的对象(\label)在同一页,并且不指定选项时,\vref\ref命令的表现是一样的。那么,如果引用和被引用的对象在不同页呢?

在讲这个之前,我们讲一个实用的包,hyperref可以将引用字符串设置成超链接。可以设置特定的颜色,并且可以跳转。它对目录也同样有效。例如,在下面的例子中,我们将所有引用字符串设置成蓝色,并且只要在文档中点击它,就可以跳转到它所引用的对象所在的位置。hyperref的更多作用我们放置后面讲,在这里,为了使演示效果更好,我们提前使用它。

在引用和被引用的对象在不同页的时候,又分为几种情况。第一种是被引用的对象在当前引用的前面一页,这种情况下则会显示: “索引字符串+on the preceding page”(即,在原本的引用字符串后面增加额外的关于页码的信息,如3.3 on the preceding page),也就是在上一页的意思,也可能显示: “索引字符串+on the facing page”,在对面一页的意思。第二种情况是被引用的对象在当前引用的后面一页,这种情况下则会显示: “索引字符串+on the following page”,在下一页的意思,或者"索引字符串+on the facing page"。实际上,“索引字符串+on the facing page"是以上两种情况中的特殊情况,当我们使用双页模式的时候(book类默认是双页的,见009篇),就会分为左手页和右手页,如果引用和被引用的对象一个在左手页一个在右手页(不管谁在左谁在右),就会出现索引字符串后面有"on the facing page"的情况,意思是在对面的那一页。如果引用和被引用的对象距离超过一页,那么则会显示"索引字符串+on page x”,其中x是页码。而如果引用和被引用的对象在同一页时,就如我们一开始所说,和\ref一样,只显示"索引字符串"。这里演示一下:

\documentclass{book}
\usepackage[a5paper,margin=1.5in]{geometry}
\usepackage[nospace]{varioref}
\usepackage{kantlipsum} %生成伪文本
% 将引用设置为超链接
\usepackage[colorlinks=true,linkcolor=blue]{hyperref}
\begin{document}
\chapter{A chapter}
\vref{test}

\kant[1]

\vref{test}

\kant[2]

\label{test}

\kant[3]

\vref{test}
\chapter{A chapter two}
\vref{test}
\end{document}

这段代码生成页数较多,而原理并不复杂,自行编译一下即可,不再一一截图。

那么,如果我们指定了选项same-page,会有什么作用呢?这个选项只对引用和被引用对象在同一页的情况有效。也就是说,在这种情况下,我们在其中输入的文本,就会显示在索引符串的后面。例如,我们将前面的所有\vref命令都指定选项on the same page,也就是改为\vref[on the same page]{test},那么文档的第二页的引用"1"会变成"1 on the same page"。而其他页的引用均不变。

我们可以看出,\vref\ref\pageref整合到了一起,并且内置了一些判断,这正是我们前面致力于实现的。要注意的是,如果我们将页码的格式变成非阿拉伯数字,例如,如果我们在文档中声明了\pagenumbering{roman}命令(将页码显示为罗马数字),那么"on the preceding/following/facing page"都会转换成on page x的格式(其中x是一个罗码数字,即页码的roman格式),只有引用当前页对象的情况不受影响。如果我们在上面的例子中增加一行\pagenumbering{roman},那么除了第二页的引用不变,其他页都会变成"索引字符串 + on page x"的格式。

\vref\Vref的区别就像\ref\Ref的区别。可以说,\Vref就是将\vref定义中的\ref换成了\Ref,以能够将索引字符串中的首字母大写。其他的特性均示\vref相同。

它们的星号形式,也就是\vref*\Vref*,和原形式的不同之处仅仅是: 星号形式的命令可以将hyperref的作用无效化。也就是说,如果你使用的是\vref*或者\Vref*,那么生成的索引字符串就不再是超链接了,而是普通的文本,既没有颜色也不能跳转。如果你不使用hyperref包,那么这两种形式的结果都是一样的。

  • 16
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值