LaTeX教程(004)- LaTeX \LaTeX LATEX文档结构(04)
2.2.1 标题编号
为了支持编号, LaTeX \LaTeX LATEX为每一个划分单位使用了一个 计数器,并用这些计数器组合成标题编号。例如,通常2.1表示第二章第一节的编号,这里2是由章(chapter)的计数器提供的,1是节(section)的计数器提供的,低级的划分单位的编号建立在更高级的划分单位编号的之上,以此类推,层层累加。
回顾一下上一篇的中我们使用的一个样例,当时我们特别强调了,\subsubsection
命令生成的标题既没有编号,在目录中也没有显示其条目。标题编号到第几层(即编号的深度),由一个叫secnumdepth
的计数器控制。例如,在book类中,secnumdepth
的值默认是2,因此,从最高级标题\part
到2级标题\subsection
都会被编号。我们使用一个命令来改变它的值,例如,\setcounter{secnumdepth}{1}
,可以将它的值改为1。这个命令可以放在导言区,也可以放在正文中。命令会即时生效。我们演示一下它的作用:
\documentclass{book}
\usepackage{ctex}
\usepackage[a5paper]{geometry}
\begin{document}
\tableofcontents
\chapter{这是第一章}
\section{这是第一章的第一节}
\subsection{这是第一章第一节的第一个子节}
\subsubsection{这是一个子子节}
\end{document}
这是一段secnumdepth
的值没有被修改过的book类文档,编译结果如下(这里我们只展示目录和标题):
现在在导言区在加上一行代码,以将编号深度改为1:
\setcounter{secnumdepth}{1}
目录和导言区就会发生变化:
可以看到,这次仅编号到1级标题,\subsection
没有被编号,因为它是二级标题。我们可以在正文中随时使用该命令修改编号的深度,改动会对命令之后的所有内容生效,直到再一次使用该命令。我们再演示一次:
\documentclass{book}
\usepackage{ctex}
\usepackage[a5paper]{geometry}
\begin{document}
\tableofcontents
\chapter{这是第一章}
\section{这是第一章的第一节}
\subsection{这是第一章第一节的第一个子节}
\subsubsection{这是一个子子节}
\setcounter{secnumdepth}{1} %从这里开始将编号深度改为1
\chapter{这是第二章}
\section{这是第二章的第一节}
\subsection{这是第二章第一节的第一个子节}
\subsubsection{这是一个子子节}
\setcounter{secnumdepth}{3} %从这里开始将编号深度改为3
\chapter{这是第三章}
\section{这是第三章的第一节}
\subsection{这是第三章第一节的第一个子节}
\subsubsection{这是一个子子节}
\end{document}
编译结果如下:
注意第三章的子子节,尽管我们将编号深度修改为3,子子节被编号了,但是它仍然没有在目录中显示出来。这是因为secnumdepth
的值只能影响编号深度,不能影响目录的结构深度。影响目录的结构深度的一个计数器是tocdepth
,我们后面再讲。
如果我们想让所有标题都不编号,最方便的办法是将secnumdepth
的值设置为-2,而不是一直使用带星号的划分命令。这种方法的好处是,目录仍然可以生成。
如果我们不知道当前的编号深度是多少,只是想在此基础上加上(或减去)几级,那么可以使用\addtocounter
命令。例如,在上面的例子中,我们可以将第三章前面的\setcounter{secnumdepth}{3}
换成\addtocounter{secnumdepth}{2}
,意为将当前的secnumdepth
的值加2。如果想减小secnumdepth
的值,可以用同一个命令加上一个负数,例如: \addtocounter{secnumdepth}{-1}
,它可以将当前的secnumdepth
的值减1。
每一个章节划分命令都有一个与之关联的计数器,默认情况下,计数器的名称和与之对应的章节划分命令相同,例如,\section
对应的计数器就是section
,\chapter
对应的计数器就是chapter
。这个计数器存储了它所对应的章节划分命令的数量。我们可以通过使用\the+counter
形式的命令将这些已经格式化的完整编号打印出来:
\documentclass{book}
\usepackage{ctex}
\usepackage[a5paper]{geometry}
\begin{document}
\tableofcontents
\chapter{这是第一章}
\section{这是第一章的第一节}
\thechapter % 输出第一章的编号
\thesection % 输出第一章第一节的编号
\end{document}
输出结果如下:
实际上,在这个例子中,计数器section
的值是1,但为什么\thesection
输出的是1.1呢?这和编号命令\the+counter
的定义结构有关。
在了解编号命令的定义结构之前,我们先要了解计数器的定义结构。
从前面的例子中,我们可以观察到,每当一个计数器发生变化,它的下一级计数器会被重置,例如,第一章(chapter)有很多节(section),但当第二章开始,section
又会被重置为1。当然,重置本身也是一种变化,此时section
也发生了变化,subsection
也会被重置,以此类推。这是因为计数器就是以这种层层嵌套的形式定义的。例如,在report以及book的类文件中,包含以下声明:
\newcounter{part} % (-1) parts
\newcounter{chapter} % (0) chapters
\newcounter{section}[chapter] % (1) sections
\newcounter{subsection}[section] % (2) subsections
\newcounter{subsubsection}[subsection]% (3) subsubsections
\newcounter{paragraph}[subsubsection] % (4) paragraphs
\newcounter{subparagraph}[paragraph] % (5) subparagraphs
我们用\newcounter
命创建一个计数器,它可以创建一个独立的计数器,也可以使用它的选项为该计数器设置一个重置条件。例如\newcounter{section}[chapter]
表示创建一个计数器section
,并且它随计数器chapter
的变化而重置。
这些声明中,默认用这个命令定义了所有的章节划分命令的计数器,可以看到,chapter
计数器是独立的,并不会在part
变化时重置,如果我们想让chapter
随part
重置,可以将类文件中的\newcounter{chapter}
替换为\newcounter{chapter}[part]
。
当然,如果我们只是想改变当前的文档中某个计数器的行为,那么最好不要改动类文件。对于已有的计数器,我们可以在当前的文档内部使用命令\counterwithin
或者\counterwithout
来改变它的行为。例如,\counterwithin{chapter}{part}
可以将chapter
计数器嵌入到part
中,即part
变化时,chapter
重置。我们可以演示一下:
\documentclass{book}
\usepackage{ctex}
\usepackage[a5paper]{geometry}
\begin{document}
\tableofcontents
\counterwithin{chapter}{part} % 将chapter嵌入到part中
\part{这是第一部分}
\chapter{这是第一章}
\part{这是第二部分}
\chapter{这是第二章}
\end{document}
输出的结果我们仅截取标题:
可以看到,Part II中,chapter
的计数器仍是从1开始的,这意味着它被重置了。并且\chapter
的编号也与\part
的计数器关联起来了。
\counterwithout
命令可以取消某种嵌套,例如,默认情形下,subsection
计数器会在section
变化重置,我们可以使用\counterwithout
来取消这种结构:
\documentclass{book}
\usepackage{ctex}
\usepackage[a5paper]{geometry}
\begin{document}
\tableofcontents
\counterwithout{subsection}{section} %取消嵌套
\chapter{这是第一章}
\section{这是第一节}
\subsection{这是第一节的第一个子节}
\subsection{这是第一节的第二个子节}
\section{这是第二节}
\subsection{这是二节的第一个子节}
\end{document}
输出结果如下:
可以看到,子节的计数器不会被重置,并且编号也独立了。
在讲编号的定义结构之前,我们还要先了解一个概念,即如何将一个计数器格式化输出。一个计数器的值是多少,我们是无法直接看到的。想看到,需要将他们以某种格式打印出来,这一操作叫作格式化输出。
例如,我们如果想知道当前的文档中,默认的编号深度是多少,就可以格式化输出计数器secnumdepth
:
\documentclass{book}
\usepackage{ctex}
\usepackage[a5paper]{geometry}
\begin{document}
\Roman{secnumdepth}、 % 以大写罗马数字形式输出secnumdepth的值
\arabic{secnumdepth}、 % 以阿拉伯数字形式输出secnumdepth的值
\alph{secnumdepth} % 以小写字母形式输出secnumdepth的值
\end{document}
输出结果如下:
通常我们看到的都是阿拉伯数字。常用的格式化输出命令还有\Alph
(大写字母)、\roman
(小写罗马数字)等等。我们不再一一列举。
当我们使用一个划分命令时,系统在底层调用了这些格式化的命令,以便我们能看到它们的编号。那么,这些编号是如何组合起来,并且封装到\the+counter
命令中的呢?例如,我们可以观察到,节的编号是"计数器chapter的值+一个点.+计数器section的值",而我们只需要使用\thesection
就可以将它打印出来。
在这之前,我们先了解一下
LaTeX
\LaTeX
LATEX的宏定义功能。如果我们有一经常输入的字符串,我们就可以将它定义成一个命令,使用\newcommand
命令可以实现这一目的。如果我们声明了\newcommand{\A}{BCDEFG……}
,那么我们每次在正文中输入\A,
LaTeX
\LaTeX
LATEX就会将它展开成BCDEFG。\A是一个命令,是我们要自定义的一个命令,名称自取,只要不与已有的命令重复即可。BCDEFG是我们要将其定义成\A的东西,可以是任何合法的字符串,包括命令。我们可以做个演示:
\documentclass{book}
\usepackage{ctex}
\usepackage[a5paper]{geometry}
\newcommand{\A}{BCDEFG} % 将\A定义成BCDEFG
\newcommand{\T}{\LaTeX} % 将\T定义成\LaTeX
\begin{document}
\A
\T
\end{document}
输出结果如下:
对于一个已经存在的命令,我们可以使用\newcommand
命令重定义它,例如,我们可以在上面的例子中增加一行\renewcommand{\LaTeX}{这是我们重定义的latex}
,那么输出结果就会变成:
我们将\T定义成了\LaTeX
,又将\LaTeX
重定义成了"这是我们重定义的latex",因此最终输出的就是这句话。可见宏定义是可以嵌套的。
现在我们知道\chapter
命令的定义中是包含了\thechapter
的,以显示它的编号。那么\thechapter
是如何定义的呢?简单地说是
\renewcommand{\thechapter}{\arabic{chapter}}
我们可以做个演示:
\documentclass{book}
\usepackage{ctex}
\usepackage[a5paper]{geometry}
\begin{document}
\chapter{这是第一章}
这是第一章的编号: \arabic{chapter}
\end{document}
可以得到以下输出:
那么\section
是如何将编号显示为"计数器chapter的值+一个点.+计数器section的值"的呢?因为\thesection
命令的定义中包含了\thechapter
:
\renewcommand{\thesection}{\thechapter.\arabic{section}}
使用\section
时,系统底层调用了\thesection
,而\thesection
的定义是\thechapter.\arabic{section}
,由此,就得到了我们看到的编号形式。
我们也可以做个演示:
\documentclass{book}
\usepackage{ctex}
\usepackage[a5paper]{geometry}
\begin{document}
\chapter{这是第一章}
这是第一章的编号: \arabic{chapter}
\section{这是第一节}
这是第一章第一节的编号: \thechapter.\arabic{section}
\section{这是第二节}
这是第一章第二节的编号: \thechapter.\arabic{section}
\end{document}
编译:
同样,\thesubsection
的定义中包含了\thesection
:
\renewcommand\thesubsection{\thesection.\arabic{subsection}}
以此类推,我们不再一一演示。
我们知道了编号的原理,就可以试着重定义它们,改成我们想要的样子了,例如,我们想将所有的\section
计数器输出为大写字母,就可以这样做:
\documentclass{book}
\usepackage{ctex}
\usepackage[a5paper]{geometry}
\renewcommand\thesection{\thechapter.\Alph{section}} % 将\section的编号定义成大写字母
\begin{document}
\chapter{这是第一章}
\section{这是第一节}
\section{这是第二节}
\subsection{这是一个子节}
\end{document}
编译:
这样会显得很奇怪,实际上我们可以将\thesection
的定义中的\thechapter.
去掉,这样会更好看些。
如果我们想给编号加上一个方框,那么重定义the+counter
命令并不是一个好办法,例如:
\documentclass{book}
\usepackage{ctex}
\usepackage[a5paper]{geometry}
\renewcommand{\thesection}{\fbox{\thechapter.\arabic{section}}} %重定义\thesection,\fbox命令可以在一个对象外面加上一个可见的盒子
\begin{document}
\chapter{这是第一章}
\section{这是第一节}
\section{这是第二节}
\label{sec:wrong}
\subsection{这是一个子节}
我们在引用 \ref{sec:wrong} 节时会出现我们不想要的结果。% \label和\ref命令是交叉引用命令,我们后面再讲
\end{document}
编译:
可以看到,如果给一个编号通过重定义的方式加上一个方框,那么他的次级标题的编号就会变得难看,交叉引用的效果(可见计数器的显示命令也被交叉引用的机制使用)也不是我们想要的(通常引用不带样式)。
我们可以重定义
LaTeX
\LaTeX
LATEX的内部命令\@seccntformat
,它负责排版标题的编号部分。但改动内部命令是不太安全的行为,最方便的办法是使用titlesec
包:
\documentclass{book}
\usepackage{ctex}
\usepackage[a5paper]{geometry}
\usepackage{titlesec}
\titlelabel{\fbox{\thetitle}\hspace{0.5em}} %我们使用\titlelabel给标题的标头加上一个可见的盒子,而不去重定义编号的样式。0.5em是方框到标题之间的间隙,你可以去掉\hspace{0.5em}再编译一次对比一下效果
\begin{document}
\chapter{这是第一章}
\section{这是第一节}
\section{这是第二节}
\label{sec:OK}
\subsection{这是一个子节}
我们在引用 \ref{sec:OK} 节时不会出现问题。
\end{document}
编译:
关注【年轻人 你渴望力量么】