LaTeX教程(017)-文档结构(17)
2.4.2cleveref
包-索引文本的智能格式化
在前面的内容中我们已经看到,基于索引中使用的计数器,为索引文本格式化提供了一些轻便的支持。cleveref
包(作者Toby Cubitt)则为这一功能提供了重量级的支持。并且可以对数字引用和页码引用进行排序,适当地缩小范围。varioref
包的命令\vref
,\Vref
, 以及\vpageref
均被增强,以支持多个key
和引用的格式化。所有格式化的内容都在导言区,这使得cleveref
成为一个全面而强大的方案。
\cref{key-list}
\cref*{key-list}
\Cref{key-list}
\Cref*{key-list}
cleveref
包提供的主要命令是\cref
。它可以接收一个key
,就像\ref
那样。也可以接收多个key
,这些key
之间用逗号隔开。它将这些key
对应的索引文本,根据它们自身的类型进行格式化,例如,在这些索引文本的前面添加前缀,"section","fig"等。也可能会添加一些其他的装饰,例如在公式编号的两边添加一对圆括号。
如果给定一个由多个key
组成的列表,它会根据需要显示复数形式(例如一个公式显示eq.,多个公式显示eqs.),对于更长的列表,它知道适当地连接。例如,它可以区分哪些是成对的引用,哪些是多个单独的引用,哪些是一个连续的范围,并且可以处理这些组合。
根据以往的经验,读者可能已经想到\Cref
的作用了。它和\cref
的不同之处是,\Cref
会判断生成的索引文本是否出现在句首,如果出现在句首,则首字母大写(如果索引文本是以单词开头的话)。但其实这里还有一个新的差异,那就是\cref
生成的索引文本的前缀,有些会使用缩写,如"fig. xx","eq. (xx)"等等,而\Cref
总是会生成完整的单词,如"figure","equation"等等。
和前面一样,它们的星号形式均有抑制hyperref
链接的特性。
我们用一个例子演示一下:
\documentclass{article}
\usepackage[a5paper,margin=1.5in]{geometry}
\usepackage{amsmath}
\usepackage[colorlinks=true,linkcolor=blue]{hyperref}
\usepackage{cleveref}
\begin{document}
\section{A section}\label{sec:this}
A reference to an equation in this section looks like : ``see \cref{eq:a} in \cref{sec:this}''.
\begin{align}
a &= b \label{eq:a}\\
b &< c \label{eq:b}\\
c &< d \label{eq:c}
\end{align}
\Cref{eq:c,eq:a,eq:b} above are \ldots
\end{document}
编译:
可以看到,\cref
生成的公式的索引文本和标题的不同,公式的索引文本的前缀是缩写"eq.",并且用一对圆括号公式的编号围起来,而标题的索引要本的前缀是"section"。\Cref
生成的公式的索引文本,前掇是"Equations",是一个完整的单词,并且由于它出现在句首,首字母大写。
留意索引代码\Cref{eq:c,eq:a,eq:b}
,可以看到我们是将这些key
乱序输入的,但是在生成的文档中,它们仍然被正确地排序了,结果呈现了一个正确的范围,并且由于我们输入了多个key
,前缀也都变成的复数形式(equations, 或eqs.)。索引的自动排序是一个很实用的特性,编写文档时,你很可能会需要重新排列某些内容,这可能会导致这些key
也跟着变动。而此时如果没有自动排序的话,索引就会生成像"see figures(1),(3),and(2)"这样的文本。
我们在前面的例子中多添加两行公式,并且使用一个不同的间隔符号,就可能会出现不同的情形:
\documentclass{article}
\usepackage[a5paper,margin=1.4in]{geometry}
\usepackage{amsmath}
\usepackage[colorlinks=true,linkcolor=blue]{hyperref}
\usepackage{cleveref}
\begin{document}
\section{A section}
\begin{align}
a &= b \label{eq:a}\\
b &< c \label{eq:b}\\
c &< d \label{eq:c}\\
a &< c \label{eq:d}\\
b &< d \label{eq:e}
\end{align}
\Cref{eq:c,eq:b,eq:a,eq:d,eq:e} are sorted and \cref{eq:c,eq:b,eq:a,eq:e} are sorted with a gap. But compare these results with referencing \cref{eq:c,,eq:b,eq:a,eq:d,eq:e}! Surprised?
\end{document}
编译:
我们知道这里公式(1)到(5)是一个连续的范围,但是最后一个\cref
命令生成的内容却是"eqs.(1) to (3), (4) and (5)",这是为什么呢? 注意观察最后一个\cref
命令的参数,我们在eq:c
的后面放了两个逗号,正是这两个逗号,使得在排序之后的key
时,逗号前面的key
是前面一组的最后一个索引。也就是说,eq:c
是前面那一组的最后一个引用,而eq:c
后面的key
在下一组。注意先排序,再分组,尽管我们将eq:a
和eq:b
都写在了这两个逗号的后面,但是由于它们排序后在eq:c
的前面,所以它们也被分到了前面的那组,即公式(1)到(3)。
你可以在\cref
以及\Cref
的参数中放一些不同类型的key
,cleveref
会选将索引分类,再在同类中排序。当然,前提是这些不同类型的索引是相容的,否则你可能会得到一些奇怪的范围结构。我们将前一个例子稍作改动:
\documentclass{article}
\usepackage[a5paper,margin=1.4in]{geometry}
\usepackage{amsmath}
\usepackage[colorlinks=true,linkcolor=blue]{hyperref}
\usepackage{cleveref}
\begin{document}
\section{A section}\label{sec:one}
\begin{align}
a &= b \label{eq:a}\\
b &< c \label{eq:b}\\
c &< d \label{eq:c}\\
a &< c \label{eq:d}\\
b &< d \label{eq:e}
\end{align}
\Cref{eq:c,,eq:b,eq:a,eq:d,eq:e,sec:one,sec:two}
\section{A section too}\label{sec:two}
\end{document}
编译:
cleveref
默认带有排序和范围精简的功能,排序是指将乱序的key
生成顺序的索引,而范围精简功能是指将多个连续的索引缩写为一个范围,例如在前面的例子中,它将公式(1),公式(2)...公式(5)缩写成了eqs.(1) to (5)。通常默认的这些功能正是我们需要的,但如果你有特殊的需求,也可以通过指定包选项来修改它。在调用cleveref
时,如果指定sort
选项,将只有排序功能,而没有范围精简功能,如果指定compress
选项,则只有范围精简功能,而不排序,如果指定nosort
选项,则两个功能都没有,指定sort&compress
选项,则两个功能都有(也即是默认情形)。我们知道使用\Cref
会使出现在句首的索引前缀单词首字大写,而如果我们指定了capitalise
选项,那么每一个索引前缀单词的首字母都将大写,且不论使用的是\Cref
还是\cref
。我们将前面的例子稍作更改(加两个包选项):
\documentclass{article}
\usepackage[a5paper,margin=1.4in]{geometry}
\usepackage{amsmath}
\usepackage[colorlinks=true,linkcolor=blue]{hyperref}
\usepackage[sort,capitalize]{cleveref}%加两个包选项
\begin{document}
\section{A section}\label{sec:one}
\begin{align}
a &= b \label{eq:a}\\
b &< c \label{eq:b}\\
c &< d \label{eq:c}\\
a &< c \label{eq:d}\\
b &< d \label{eq:e}
\end{align}
\cref{eq:c,,eq:b,eq:a,eq:d,eq:e,sec:one,sec:two}
\section{A section too}\label{sec:two}
\end{document}
编译:
可以看到,索引被排序了,但是没有缩写成范围,并且所有的索引文本的前缀都是首字母大写的。
cleveref
还支持很多语言选择,如italian
,german
等(没有中文)。有需要的读者可以翻阅包文档,自行探索。
还有一个实用的选项,noabbrev
,它会禁用缩写,而将所有前缀变成完整的单词,如此一来,使用\cref
也总会生成完整的前掇。
最后,如果你同时使用了cleveref
包和hyperref
包,那么索引就会生成超链接(除非你使用的是星号形式的索引命令)。默认情况下,超链接文本,也就是前面的例子中那些蓝色的、你点了可以跳转的文本,仅限于那些编号,并且不包括其他的材料(观察上面的例子)。但如果你指定了nameinlink
,就可以扩大超链接文本的范围。我们将前面的例子稍作修改:
\usepackage[nameinlink,noabbrev]{cleveref}
%只改这行即可,其他的不变
编译:
可以看到,超链接文本扩大到了括号以及前缀上。
在有些特殊情形下,你可能只想要一个索引生成的文本,而不想要索引值(通常是那些编号),此时我们就可以使用以下这些命令:
\namecref{key}
\namecrefs{key}
\nameCref{key}
\nameCrefs{key}
\lcnamecref{key}
\lcnamecrefs{key}
我使演示一下:
\documentclass{article}
\usepackage[a5paper,margin=1.4in]{geometry}
\usepackage{amsmath}
\usepackage[colorlinks=true,linkcolor=blue]{hyperref}
\usepackage{cleveref}
\begin{document}
\section{A section}\label{sec:one}
\begin{align}
a &= b \label{eq:a}\\
b &< c \label{eq:b}\\
c &< d \label{eq:c}\\
a &< c \label{eq:d}\\
b &< d \label{eq:e}
\end{align}
\section{A section too}\label{sec:two}
some text ...
\namecref{eq:a}
\namecrefs{eq:a}
\namecref{sec:one}
\namecrefs{sec:two}
\nameCref{eq:c}
\nameCrefs{eq:d}
\lcnamecref{eq:e}
\lcnamecrefs{sec:one}
\end{document}
编译:
观察这些输出,可以很容易看出,\namecref{key}
得到的文本就是\cref{key}
生成的文本去掉索引值(通常是那些编号),而后面有个"s"的命令,如\namecrefs{key}
,则会得到\namecref{key}
的复数形式。前四个命令都是这种规律,\nameCref{key}
得到的通常是首字母可以大写的、完整的前缀,而\nameCrefs{key}
到得的则是前者的复数形式。需要注意的是最后两个命令,\lcname...
的形式的命令得到的总是小写的文本,哪怕你指定了capitalize
选项也不行。
要注意是的,这六个命令不支持key
列表,每个命令的参数中只能放置一个key
。
还有一些命令,只保留索引值,不生成其他文本。如\labelcref{key-list}
和\labelcpageref{key-list}
。它们分别保留索引的编号和页码。并且默认都保留了自动排序功能和范围精简功能。但是要注意,尽管它们都支持key
列表,但是不支持不同类型的key
。因为没有了能够区分索引类型的前缀等文本,因此禁止将不同类型的key
混在一起。
我们用一个例子演示:
\documentclass{article}
\usepackage[a5paper,margin=1.4in]{geometry}
\usepackage{amsmath}
\usepackage[colorlinks=true,linkcolor=blue]{hyperref}
\usepackage{cleveref}
\begin{document}
\section{A section}\label{sec:one}
\begin{align}
a &= b \label{eq:a}\\
b &< c \label{eq:b}\\
c &< d \label{eq:c}\\
a &< c \label{eq:d}\\
b &< d \label{eq:e}
\end{align}
\labelcref{eq:c,,eq:b,eq:a,eq:d,eq:e}
\labelcpageref{sec:one,sec:two}
\section{A section too}\label{sec:two}
\end{document}
编译:
除了使用一串连续的key
来生成一个范围之外,还可以使用两个key
确定一个范围,可以使用如下命令实现这一点:
\crefrange{keyfirst}{keylast}
\crefrange*{keyfirst}{keylast}
\Crefrange{keyfirst}{keylast}
\Crefrange*{keyfirst}{keylast}
它其实是将两个索引用"to"连起来,因此使用它的时候,要确保keyfirst
和keylast
不是相连的,否则就会出现如下情形:
\documentclass{article}
\usepackage[a5paper,margin=1.4in]{geometry}
\usepackage{amsmath}
\usepackage[colorlinks=true,linkcolor=blue]{hyperref}
\usepackage{cleveref}
\begin{document}
\section{A section}\label{sec:one}
\begin{align}
a &= b \label{eq:a}\\
b &< c \label{eq:b}\\
c &< d \label{eq:c}\\
a &< c \label{eq:d}\\
b &< d \label{eq:e}
\end{align}
\section{A section too}\label{sec:two}
\Crefrange{eq:a}{eq:e}
\crefrange{sec:one}{sec:two}
\end{document}
编译:
结果中是"sections 1 to 2"并不是我们想要的,在只有两个对象时,我们用"and"连接,此时更建议使用\cref
。
cleveref
也提供了一套用来索引页码的命令:
\cpageref{key-list}
\Cpageref{key-list}
\cpagerefrange{keyfirst}{keylast}
\Cpagerefrange{keyfirst}{keylast}
根据以往的经验,我们基本上可以看出这几个命令的作用了。最基本的命令是\cpageref{key-list}
,它和\cref
一样,支持key
列表,并且一个命令的参数中可以输入不同类型的key
。它默认有自动排序和范围精简功能。而\Cpageref
和\cpageref
不同的是,它生成的前缀如果出现在句首,首字母会大写,并且总是使用完整单词。\cpagerefrange
和\Cpagerefrange
,与我们前面讲过的\crefrange
和\Crefrange
命令的使用方式相同,唯一不同的只是\cpagerefrange
索引的是页码。对这四个命令,我们不再一一演示。
如果varioref
包和cleveref
一起使用,那么varioref
包命令的一些功能就会发生改变,这可能是因为cleveref
重定义了某些varioref
的命令,以支持key
列表,而不是单个key
。我们将这些命令列一下:
\vref*{key-list}
\Vref*{key-list}
\vrefrange*{keyfirst}{keylast}
\vpageref*{key-list}
\vpagerefrange*{keyfirst}{keylast}
并且要注意的是,如果这两个包一起使用了,这些命令就不支持可选参数了。例如,如果使用
\vrefrange*[same page]{keyfirst}{keylast}
就会报错。
为了支持索引文本的首字母的大写,cleveref
还定义了\Vrefrange
,\Vpageref
以及\Vpagerefrange
等命令,而这些是varioref
包里没有的。
我们用一个例子演示一下:
\documentclass{article}
\usepackage[a5paper,margin=1.5in]{geometry}
\usepackage{kantlipsum}
\usepackage[colorlinks=true,linkcolor=blue]{hyperref}
\usepackage[nospace]{varioref}
\usepackage[noabbrev]{cleveref}
\begin{document}
\renewcommand\theequation{\thesection.\arabic{equation}}
\section{Test}
Observe \vrefrange{A}{C} and in particular \vref{B,C}.
\begin{equation}
a=b\label{A}
\end{equation}
Here is a second equation that appears
on the next page \ldots
\kant[1]
\begin{equation}
b<c\label{B}
\end{equation}
\ldots and finally one more equation:
\begin{equation}
a<c\label{C}
\end{equation}
\end{document}
出于篇幅考虑,这里不将编译结果帖出来了,请读者自行编译一下。