每一份投稿规范都写着同一句话:缩略语要在首次出现时写出全称,此后用缩写即可。靠人手几乎守不住。挪动一节,「首次」的位置就跟着移动;漏改了关键的那一处,审稿人一定会发现。LaTeX 的 glossaries 宏包(以及后继的 glossaries-extra)把这条规则交给机器执行。术语或缩略语在导言区定义一次,正文中只写 \gls{key}:首次使用会自动展开,顺带只有真正用过的词条才会排好序出现在文末的术语表里。本页沿着完整路径走一遍——定义词条、\newacronym、运行 makeglossaries、\printglossary——并先行排除术语表变成空白的四种原因,其中三种连警告都不会给。
定义一次,随处调用:newglossaryentry 与 gls
在导言区写 \newglossaryentry{key}{name=..., description=...},正文中用 \gls{key} 调用。第一个参数 key 是你自定的标签;name 是会被印出来的文字,description 是将出现在术语表里的说明。要记住的关键是:\gls 同时做两件事——把 name 插入当前位置,并向辅助文件写入一条记录,声明这个词条属于术语表。因此,只定义却从未用 \gls 调用过的词条根本不会出现。只列出用过的词条是设计如此,而非缺陷。
各种变体只在命令开头的字母上有别。句首用 \Gls{key};复数用 \glspl{key};两者兼有则用 \Glspl{key}。自动生成的复数只是在 name 末尾加个 “s”,所以像 matrices 这样的不规则形式必须用 plural key 明确写出。若正文中的写法要不同于显示名,就设 text;相关符号放进 symbol key,用 \glssymbol{key} 调出;只想插入说明时用 \glsdesc{key}。若说明长到跨越多个段落,改用 \longnewglossaryentry。另外,调用不存在的 key 会以 ! Package glossaries Error: Glossary entry ... has not been defined. 中止——拼错时不被默默忽略,在这里是优点。
\usepackage{glossaries}
\makeglossaries % opens the glossary files -- required
\newglossaryentry{set}{%
name={set},
description={a collection of distinct objects}%
}
\newglossaryentry{matrix}{%
name={matrix},
plural={matrices}, % irregular plural, spelled out
description={a rectangular array of numbers}%
}
\begin{document}
\Gls{set} theory studies a \gls{set}; linear algebra studies \glspl{matrix}.
\printglossaries
\end{document}| 命令 | 输出 | 用途 |
|---|---|---|
\gls{set} | set | 普通引用;同时也是把词条登记进术语表的动作 |
\Gls{set} | Set | 句首把首字母大写 |
\glspl{matrix} | matrices | 复数;默认是 name 加 s,可用 plural key 覆盖 |
\Glspl{matrix} | Matrices | 复数并首字母大写 |
\glsdesc{set} | a collection of distinct objects | 只插入 description 字段的内容 |
\glssymbol{sigma} | σ | 调出存放在 symbol key 中的符号 |
把缩略语交给机器:newacronym 与首次展开
用 \newacronym{key}{short}{long} 定义,之后只写 \gls{key} 即可。short 是缩写(例如 SVM),long 是全称(support vector machine)。同样写两次 \gls{svm},第一次输出「support vector machine (SVM)」,之后都只输出「SVM」。这正是机器接手那条人手守不住的规则之处:首次使用标志按词条跟踪,并且遵循处理的先后顺序,所以挪动一节时展开的位置也随之移动。稿件重排之后不会自相矛盾。
若希望从某处起再次写出全称——比如某一章要能独立阅读——就用 \glsreset{key};要一次重置全部词条则用 \glsresetall。若要把缩略语单独汇成一份列表,用 \usepackage[acronym]{glossaries} 加载宏包:这样就有了两份互相独立的列表,术语表和缩略语表,各自配有一组辅助文件。另外,如果同时加载了 glossaries-extra,\newacronym 会成为带 category=acronym 的 \newabbreviation 的别名——所以若是新开项目,直接写 \newabbreviation 可以立刻用上丰富的缩略语样式。
\usepackage[acronym]{glossaries} % a second, separate list
\makeglossaries
\newacronym{svm}{SVM}{support vector machine}
\begin{document}
\gls{svm} is a classifier. % -> support vector machine (SVM)
Another \gls{svm} follows. % -> SVM
\glsreset{svm} % start a chapter that must stand alone
\gls{svm} again in full. % -> support vector machine (SVM)
\printglossary[type=main,title={Glossary}]
\printglossary[type=\acronymtype,title={Acronyms}]
\end{document}构建:makeglossaries 把 .glo 变成 .gls
LaTeX 只负责记录词条,既不排序也不排版。第一次运行时,\makeglossaries 会产生一个 .ist 文件——写着排序规则的样式文件——凡被 \gls 调用过的词条则积存在 .glo 中。这时插入外部程序 makeglossaries,它会亮出底牌:运行后会打印出 makeindex -s mydoc.ist -t mydoc.glg -o mydoc.gls mydoc.glo。这正是制作索引所用的同一个 makeindex。排好序的 .gls 一旦生成,再跑一次 LaTeX 把它读进来即可。
pdflatex mydoc # writes mydoc.glo (and mydoc.ist)
makeglossaries mydoc # sorts it: no file extension here
pdflatex mydoc # reads mydoc.gls, prints the glossary
# what makeglossaries actually runs, once per glossary type:
# makeindex -s mydoc.ist -t mydoc.glg -o mydoc.gls mydoc.glo
# makeindex -s mydoc.ist -t mydoc.alg -o mydoc.acr mydoc.acn有两份术语表,就有两组文件。默认术语表走 .glo → .gls,记录写在 .glg;加上 acronym 选项后,缩略语表使用 .acn → .acr(记录 .alg),于是 makeglossaries 会调用 makeindex 两次。正是这份「知道一共有几份列表,并按需运行相应次数」的职责,让我们插入 makeglossaries 而不是自己敲 makeindex。该脚本用 Perl 写成,所以在没有 Perl 的环境(Windows 上很常见)里改用 makeglossaries-lite:同样的工作,实现为由 texlua 运行的 makeglossaries-lite.lua。
术语表一片空白时:四种原因,其中三种毫无声息
最常见的原因是忘了运行 makeglossaries,而这种失败几乎不给你任何线索。没有 .gls,术语表就连标题一起不出现——不是留下一个空框,而是那里什么都不排。既无错误也无警告,只在日志深处留下一行 No file mydoc.gls.。这与索引里忘记 makeindex 是同一个陷阱,而且伪装得很好:\gls 本身从第一次运行起就能正确展开,所以只看 PDF 正文时,一切都像在正常工作。
- 没有运行
makeglossaries。 没有.gls,术语表连同标题一起不出现。没有警告,日志里只有No file mydoc.gls.。 - 导言区缺少
\makeglossaries。 输出文件根本没被打开,连.glo都不会生成,同样什么都不印。没有警告。 - 只定义了词条却没用
\gls调用。 未使用的词条不会被记录,因此不会列出。这是设计如此——想让某个词进术语表,就在正文里至少提到一次。 - 唯一会明确告诉你的,反倒是相反的错误。 写了
\makeglossaries却忘了\printglossary,会得到Package glossaries Warning: No \printglossary or \printglossaries found. (Remove \makeglossaries if you dont want any glossaries.) This document will not have a glossary.。
还有一种组合会一声不吭地出问题。如果使用 hyperref,要在 hyperref 之后加载 glossaries——这是「hyperref 最后加载」这条经验之谈为数不多的例外之一。该宏包的入门指南明确这样写着,而顺序弄反时不会有任何警告:术语表里的链接和页码只是悄悄地坏掉。请按下面的顺序排列。
\usepackage[colorlinks]{hyperref}
\usepackage{glossaries} % after hyperref, not before
\makeglossaries
% put the glossary into the table of contents as well:
% \usepackage[toc]{glossaries}输出:printglossary 的标题、类型与进入目录
\printglossaries 会输出你准备好的所有列表,\printglossary 只输出一份。选哪个取决于是否需要选项:若要让每份列表有自己的标题或样式,就传入选项,例如 \printglossary[type=main, title={术语表}];否则一行 \printglossaries 就够了。标题用词本身存放在 \glossaryname 中,可用 \renewcommand 替换。
这些标题没有编号,所以默认不会进入目录。把宏包写成 \usepackage[toc]{glossaries} 加载,就会自动列入目录,比为每份术语表各写一行 \addcontentsline 更可靠。外观本身用 \setglossarystyle{...} 切换:list(默认)基于 description 环境;altlist 让词条独占一行、说明缩进其下;long 系列则整个排成表格。说明越长,altlist 与 long 系列在可读性上的回报就越明显。
现代配置:glossaries-extra 与 bib2gls
glossaries 的首版发布于 2007 年 5 月 16 日,由 Nicola Talbot 作为旧 glossary 宏包的后继推出。同一位作者随后在 2015 年发布 glossaries-extra,2017 年发布 bib2gls。这套组合的思路完全借自文献管理:把术语存放在 .bib 文件里,bib2gls 只挑出正文中实际用到的那些,排好序再读入——正如 biber 只取被引用的文献。选择与排序这两件原本属于 makeindex / xindy 的活,由一个程序全部接手。
关键在 record 选项。写成 \usepackage[record]{glossaries-extra} 加载后,makeindex / xindy 的索引会被关闭,转而向 .aux 写入形如 \glsxtr@record{set}{}{page}{glsnumberformat}{1} 的行。bib2gls 读取这些记录,只把需要的条目写回 .glstex。正因如此,第一次运行时尚未定义任何条目才是正常的——所以 glossaries-extra 把未定义条目从错误降级为警告。第一遍出现一串 Package glossaries-extra Warning: Glossary entry ... has not been defined 完全在意料之中。这与纯 glossaries 在同样场合直接中止形成对照,两种选择都各自自洽。
@entry{set,
name = {set},
description = {a collection of distinct objects}
}
@abbreviation{svm,
short = {SVM},
long = {support vector machine}
}
@symbol{sigma,
name = {\ensuremath{\sigma}},
description = {standard deviation}
}\usepackage[record]{glossaries-extra}
\GlsXtrLoadResources[src={terms}] % terms.bib, without the extension
\begin{document}
\gls{set} and \gls{svm} are used here.
\printunsrtglossary % already sorted by bib2gls
\end{document}文档里的写法几乎没有变化。用 \GlsXtrLoadResources[src={terms}] 读取 .bib(src 是不带扩展名的文件名),术语照旧用 \gls{set} 调用。不同的是输出命令:既然 bib2gls 已经排好序,就改用 \printunsrtglossary(unsrt 即 unsorted,意为「原样输出」)。构建时用 bib2gls 取代 makeglossaries;加上 --group 会生成按首字母分组的小标题,pdflatex 也可换成 xelatex 或 lualatex。安装时有一点要留意:bib2gls 用 Java 写成,因此需要 Java 运行环境(至少 Java 8)。TeX Live 中的命令其实是一个启动 .jar 的 shell 脚本,所以在没有 Java 的机器上,一运行就会发现。
pdflatex mydoc
bib2gls --group mydoc # reads mydoc.aux, writes mydoc.glstex
pdflatex mydoc只要符号表的话,用 nomencl
若只是要在论文前面放一份符号表,用 glossaries 当然可以,但轻量的 nomencl 环节更少。在导言区放 \usepackage{nomencl} 和 \makenomenclature,在符号首次出现处用 \nomenclature{$g$}{gravitational acceleration} 标记,再在想输出列表的位置写 \printnomenclature 即可。符号属于数学内容,所以要用 $...$ 包住。构建同样借用 makeindex:\makenomenclature 产生 .nlo,用附带的样式 nomencl.ist 排序生成 .nls,再跑一次 LaTeX 读入。
pdflatex mydoc
makeindex mydoc.nlo -s nomencl.ist -o mydoc.nls
pdflatex mydoc排序依据的是符号的输入本身,逐字符比较。写下 $\sigma$,排序键就是字符串 $\sigma$,其中的美元符与反斜杠在字符编码上都排在所有字母之前。实测下来,σ 会排在 g 和 m 的前面。因此才有可选参数用来提供自定的排序键:在 \nomenclature[g-sigma]{$\sigma$}{...} 中,参与排序的是 g-sigma,而印出来的仍是符号本身。顺带一提,\nomenclature 前一行的行末应加 %:符号周围混入多余空格会打乱排序。
\usepackage{nomencl}
\makenomenclature
\renewcommand{\nomname}{List of Symbols}
% \usepackage[intoc]{nomencl} % also list it in the contents
\begin{document}
Let $g$ be gravity.%
\nomenclature{$g$}{gravitational acceleration}%
A mass $m$ feels $F = mg$.%
\nomenclature{$m$}{mass of the object}%
\nomenclature[g-sigma]{$\sigma$}{stress}% sort key, not the symbol
\printnomenclature
\end{document}标题默认是英文 “Nomenclature”,可用 \renewcommand{\nomname}{...} 替换。若要列入目录,就用 \usepackage[intoc]{nomencl} 加载。还有一些选项能自动为每一条加注:refpage 追加 “, page n”,refeq 追加 “, see equation (n)”。若想把物理常数与变量分开,可以利用刚才那个排序键的首字符重新定义 \nomgroup,把列表拆成各自带标题的小组。
- 术语和缩略语的术语表用
glossaries。 首次展开、复数、大写都替你照顾好。 - 新项目建议
glossaries-extra搭配bib2gls。 术语写在.bib里,用\printunsrtglossary输出用过的那些——只需确认机器上有 Java。 - 若只要数学符号列表,用
nomencl。 用\nomenclature标记,跑一次makeindex就完事。 - 这些都需要额外一遍编译。 中间插入外部程序(
makeglossaries/bib2gls/makeindex),然后再跑一次 LaTeX。忘了也没人会提醒你。