索引

索引,也就是书末按字母或假名顺序列出的术语和页码,只要在正文中标记术语,LaTeX 就能为你生成。关键有三步:在导言区声明 \makeindex,在需要编入索引的位置放置 \index{…},并在要输出列表的位置调用 \printindex。需要注意的是,排序不是由 LaTeX 本身完成,而是由 独立程序 makeindex(日文使用 mendex / upmendex) 负责,所以像 bibtex 一样需要额外一次处理。本页会依次介绍起始声明、条目语法(! 副条目、@ 排序键、| 页码封装)、构建流程、日文排序、样式调整,以及现代的 imakeidx 包。

索引的四个组成部分

标准索引命令由 makeidx 包提供。在导言区加载它,然后声明 \makeindex;从此以后,LaTeX 会把索引条目写入一个单独文件(.idx)。接下来只需要在正文中标记术语,并指定列表的输出位置。

  • \usepackage{makeidx} — 加载索引命令(导言区)。
  • \makeindex — 开启索引收集的声明(导言区)。没有它,\index 会被静默忽略。
  • \index{entry} — 在正文中术语出现的位置放置的标记。那里不会打印任何内容,只记录当前页码。
  • \printindex — 实际排版完成后索引的命令,通常放在文档末尾。

关键思想是,\index 是一个 不可见标记。词语本身仍要由你写在正文里,并在后面紧接 \index{…}random numbers\index{random numbers} are used)。被标记位置的页码会记录到该条目下。

编写索引条目

\index 的参数有一套专用小语法,用来表示副条目、排序键、页码范围、页码格式和交叉引用。这些依赖四个由 makeindex(不是 LaTeX)解释的 特殊字符!@|"

副条目(!)。 感叹号用来分隔层级。\index{animals!cats} 会创建主条目 “animals”,并在其下创建副条目 “cats”。重复 ! 最多可嵌套三层(mendex / upmendex 系列还能更深)。

排序键(@)。 写作 sortkey@display,可以 把用于排序的字符串与实际打印的字符串分开。符号和数学内容不会按字形自然排序,因此这点很关键。\index{alpha@$\alpha$} 会在索引中打印 α,但把它排在 “alpha” 的位置。日文中它用来给汉字提供 读音\index{さくいん@索引})。

页码范围(|(|))。 当某个主题跨越多页时,在开始位置标记 |(,在结束位置标记 |),即可得到类似 12–15 的范围。用 \index{recursion|(} 开始,之后用 \index{recursion|)} 关闭。

页码封装(|)。 在竖线后写上 接受一个参数的命令名,就只对该页码应用这个格式。\index{cat|textbf} 会把术语定义所在页码设为 粗体\index{group|textit} 会设为斜体。自定义命令名也可以使用。

交叉引用(|see / |seealso)。 同样在竖线之后,可以输出指向另一个条目的提示,而不是页码。\index{dog|see{pets}} 会得到 “dog, *see* pets”;|seealso{…} 则表示 “*see also*”。

按字面打印特殊字符(")。 如果想把 !@|" 作为普通字符放入条目,就在它前面加一个双引号。例如 \index{C"!} 会创建条目 “C!”。

符号作用示例
!副条目(嵌套)\index{animals!cats}
@排序键(控制顺序)\index{alpha@$\alpha$}
|( |)打开/关闭页码范围\index{recursion|(} … \index{recursion|)}
|cmd设置页码格式(粗体等)\index{cat|textbf}
|see“see” 交叉引用\index{dog|see{pets}}
"按字面打印下一个特殊字符\index{C"!}

构建流程(运行 makeindex)

索引不会在一次编译中完成。和 bibtex 一样,它是中间夹着独立程序的三阶段流程。 首先运行 LaTeX,会把 \index 调用收集到原始文件 file.idx。接着 makeindex 程序把它排序并格式化成 file.ind(可排版的索引)。最后再运行一次 LaTeX,让 \printindex 读取 file.ind,索引就会出现在文档中。处理日志会留在 file.ilg

document.tex
\documentclass{article}
\usepackage{makeidx}
\makeindex
\begin{document}

METAFONT\index{METAFONT} は字形を、TeX\index{TeX} は組版を担う。
ここでは乱数\index{乱数|textbf} の生成を扱い、
群\index{group@群} と環\index{ring@環} にも触れる。
アルゴリズム\index{algorithm|(} の説明はここから始まり…

% (数ページ後)
…アルゴリズム\index{algorithm|)} の説明はここで終わる。

\printindex
\end{document}

从命令行可以这样运行。-s 选择样式文件,-o 指定输出名,-t 指定日志名(省略时只替换扩展名)。

terminal
pdflatex mydoc        # writes mydoc.idx
makeindex mydoc       # mydoc.idx -> mydoc.ind (log in mydoc.ilg)
pdflatex mydoc        # \printindex reads mydoc.ind

整个流程可以由 latexmk 自动处理:当 .idx 更新时它会调用 makeindex,并按需要重新运行 LaTeX,因此无需手动敲三步。

日文索引(mendex / upmendex)

由于 makeindex 假定西文的字母顺序,日文索引使用 mendex(pLaTeX 系)或 upmendex(upLaTeX / LuaLaTeX 系,支持 Unicode)。两者都兼容 makeindex;只需在原本调用 makeindex 的位置调用它们。

terminal
uplatex mydoc                 # writes mydoc.idx
upmendex -s style.ist mydoc   # sorts kana correctly -> mydoc.ind
uplatex mydoc                 # \printindex reads mydoc.ind

最大的好处是 假名排序。使用 makeindex 时,要按五十音顺序排列条目,就必须为每个条目以 reading@display 的形式给出平假名/片假名读音,并手动统一浊点等。upmendex 使用 ICU (International Components for Unicode) 自动正确地排序假名,大大减少这项工作。再用 -d 提供 词典文件,就能批量登记汉字词读音,很多时候甚至可以完全省去 @ 读音。

经验法则:pLaTeX 用 mendexupLaTeX / LuaLaTeX 用 upmendex。通过 @ 提供读音的方法在两者中都有效(\index{さくいん@索引})。

更改索引样式(.ist)

索引的外观由 样式文件(.ist 控制,并像 makeindex -s style.ist file 这样通过 -s 传入。文件内容只是 <parameter> <value> 对的列表;字符串放在双引号中,% 之后是注释(mendex / upmendex 的样式与 makeindex 向上兼容)。

  • headings_flag — 设为非零时,在每个新组之前插入 组标题(开头字母,如 AB…,或假名组)。
  • lethead_prefix / lethead_suffix — 放在该标题前后的字符串。
  • delim_0 / delim_1 / delim_2 — 条目(各层级)与页码之间的 分隔符(例如 ", " 或点线引导)。
  • item_0 / item_1 — 插入到条目之间和层级之间的字符串(换行、缩进)。
  • preamble / postamble — 在整个索引前后输出的代码。

如果只是整理组标题的外观,像下面这样的小 .ist 就足够了。

document.tex
% style.ist
headings_flag    1
heading_prefix   "{\\bfseries "
heading_suffix   "}\\nopagebreak\n"
delim_0          "\\dotfill "

现代做法:imakeidx

imakeidx 是对 makeidx 的扩展,有两个重要优点。第一,它会在编译时 自动运行 makeindex:用 -shell-escape(允许执行外部命令)启动 LaTeX,索引就会像目录一样生成,无需手动处理。第二,它支持在一个文档中使用 多个索引(例如人名索引和主题索引)。

通过给 \makeindex 传递选项来配置它。name= 用来区分索引,title= 设置标题,intoc 将其列入目录,program= 选择排序程序(makeindex / xindy / texindy,日文可用 mendex / upmendex),options= 传递诸如 -s style.ist 的参数。写多个 \makeindex 就会得到多个索引,然后用 \index[name]{…} 分流条目,并用 \printindex[name] 输出。

document.tex
\documentclass{article}
\usepackage{imakeidx}

% two indexes; built automatically with -shell-escape
\makeindex[name=subject, title=事項索引, intoc, program=upmendex]
\makeindex[name=people,  title=人名索引, intoc, program=upmendex,
          options={-s style.ist}]

\begin{document}\index[subject]{group@群} は重要だ。
クヌース\index[people]{Knuth@クヌース} が TeX を作った。

\printindex[subject]
\printindex[people]
\end{document}
terminal
# auto-build: makeindex/upmendex is invoked for you
lualatex -shell-escape mydoc
lualatex -shell-escape mydoc   # second pass resolves page numbers

只有使用 xindy 时才需要 *完整* shell-escape,但自动构建本身都需要 -shell-escape。如果愿意,使用 imakeidx 时仍然可以像传统方式那样从外部调用 makeindex / mendex。在无法启用 -shell-escape 的环境(某些 Web 服务、严格 CI)中,自动构建不可用;请退回手动处理或交给 latexmk