在语言学论文里,真正让 LaTeX 变得非用不可的,不是树也不是音标,而是编号。「见 (1)」「与 (3b) 对照」——例句的编号会被正文反复引用,而中途插入一个例子,后面的编号就全都要挪。手工做这件事是不可能的,于是语言学家来到了 gb4e 和 expex 这类为带编号的例句与注释而生的宏包面前。本页就围绕这套编号机制展开,涵盖行间注释(\gll 与 \glt)、IPA 音标(tipa 与 Unicode)、OT 的 tableau,以及特征结构。同时也记下在 TeX Live 2024 上真正踩到的坑——标签名里只要有一个下划线,gb4e 就会连 PDF 都不产出地死掉。
带编号的例句与子例——生成 (1) 与 (1a) 的两种流派
真正在用的选项实际只有两个:gb4e 和 expex。gb4e 是在 exe 环境里排列 \ex,需要子例的地方嵌套一个 xlist 环境——(1) 下面会出现 a.、b.,而引用则搭在 LaTeX 标准的 \label / \ref 上。expex 的路数完全不同:用 \pex … \xe 括起例句,子例用 \a,而引用不用 LaTeX 的 \ref,而用它自己的 \getref。选哪个,基本取决于「你想不想搭在 LaTeX 的引用机制上」。另外 linguex(v4.3)和 covington(v2.14)也在 TeX Live 2024 里,前者的特色是能用 \ex. 这种像标点一样简短的记法书写。
| 宏包 | TeX Live 2024 | 引用机制 | 需要留意之处 |
|---|---|---|---|
gb4e | 有(更新记录停在 2010 年) | LaTeX 标准的 \label / \ref | 遇到下划线会致命崩溃,需要 \noautomath |
expex | 有(v5.1b) | 自带的 \getref / \getfullref / \nextx | LaTeX 的 \ref 不起作用,\cref 也不适用 |
langsci-gb4e | 有(日期 2022-10-21) | 与 gb4e 相同 | Language Science Press 维护的 gb4e 修订版 |
linguex | 有(v4.3) | LaTeX 标准 | 像标点一样简短的记法,例如 \ex. |
covington | 有(v2.14) | LaTeX 标准 | 汇集例句、注释与符号的老牌工具箱 |
avm | 无 | — | Manning 的 avm.sty 未收录;改用 langsci-avm |
用 gb4e 排行间注释——\gll 与 \glt
行间注释的本质是逐词的纵向对齐,这正是 \gll 的职责。第一行写原始数据,第二行写逐词注释,各行以 \\ 结束,gb4e 就会按空格切分两行并把对应的词纵向对齐。自由译文交给第三行的 \glt(需要三行对齐时用 \glll)。要留意的是,对齐的单位是「以空格分隔的词」。若原文的一个词需要两个词来注释,就用句点连成一个记号 this.one——这也是莱比锡注释规则的做法,而 TeX Live 附带的 leipzig 宏包会定义 \Erg、\Pfv 之类的标准缩写。非语法性的标记写在方括号里,例如 \ex[*]{...}。若只有一个例句,还有一种不必开 exe 环境的简写:用 \ea … \z 括起来即可。
\documentclass{article}
\usepackage{gb4e}
\noautomath % see the next section: this line prevents a fatal error
\begin{document}
\begin{exe}
\ex \label{ex:one}
\gll Kore wa rei desu.\\
this TOP example COP\\
\glt `This is an example.'
\begin{xlist}
\ex \label{ex:sub} A sub-example, printed with the label a.
\end{xlist}
\ex[*]{ Sleep colorless green ideas furiously. }
\end{exe}
See (\ref{ex:one}) and (\ref{ex:sub}).
\end{document}当 gb4e 以 ! TeX capacity exceeded, sorry [parameter stack size=20000]. 崩溃时
原因是下划线,修法就是在 \usepackage{gb4e} 之后紧接着加一行 \noautomath。仅仅写了 \label{ex_one},TeX Live 2024 的 pdfLaTeX 就会这样倒下:! TeX capacity exceeded, sorry [parameter stack size=20000].,回溯里出现 \gb@ifnextchar,最后以 ==> Fatal error occurred, no output PDF file produced! 收场。一个字节的 PDF 都不会产出。 同样的事在 \cite{smith_2020} 上也会发生——用下划线把作者和年份连起来是极普通的 BibTeX 键写法,于是刚加上参考文献,文档就坏了。加上 \noautomath,两者都能通过。
之所以如此,gb4e 自己的源码里写得很清楚。gb4e 把 _ 和 ^ 变成活动字符,好让下标和上标能直接写在正文里。效果确实惊人:载入 gb4e 后,可以在段落中直接敲 NP_i、t_j、X^0。不载入的话,同样的输入会得到 ! Missing $ inserted.——对一篇要写几百次带下标范畴标签的句法学论文而言,这是实实在在的便利。代价则是与所有以 TeX 本义使用 _ 的宏正面冲突。源码中的注记正是这么说的:本文件让 _ 与 ^ 可用于正文,因此必须在任何以 TeX 本义使用它们的文件之后载入,并提到可用 \noautomath 关闭该特性。「gb4e 要放在导言区最后」这条常见忠告,内涵就在这里。
\cref 印成 ?? 1——cref reference format for label type 'xnumi' undefined
修法是在导言区加两行:\crefname{xnumi}{example}{examples} 与 \crefname{xnumii}{example}{examples}。把 gb4e 与 cleveref 一起载入,编译本身一个错误都不会报,顺利通过,可 \cref{ex:one} 的输出却是 ?? 1。查看 .aux 会看到 \newlabel{ex:one@cref}{{[xnumi][1][]1}...},而日志里留着 LaTeX Warning: cref reference format for label type 'xnumi' undefined。cleveref 为每一种计数器都备了称呼,却不认得 gb4e 的例句计数器 xnumi(子例是 xnumii),于是在该放名称的位置塞了 ??。由于这是警告而不是错误,编译照样通过——一份带着两百处 ?? 1 的 PDF 就是这样被交上去的。加上那两行之后,\cref{ex:one} 会印出 example 1,\cref{ex:sub} 会印出 example 1a。
另一方面,常被一并提起的与 hyperref 的冲突,在 TeX Live 2024 上没有复现。无论把 \usepackage{hyperref} 放在 gb4e 之前还是之后,含 \gll 的例句都能无错排出,\ref 也正确返回 (1)。网上「gb4e 与 hyperref 不能同用」的说法,至少对同捆版本的组合而言,可以视为过时信息。不过载入顺序的原则本身依然有效——若不使用 \noautomath,请把 gb4e 放在其他使用 _ 的宏包之后。
\documentclass{article}
\usepackage{gb4e}
\usepackage{cleveref}
% Without these two lines \cref prints "?? 1" and the run still succeeds:
% LaTeX Warning: cref reference format for label type `xnumi' undefined
\crefname{xnumi}{example}{examples} % top-level examples: (1), (2), ...
\crefname{xnumii}{example}{examples} % sub-examples: (1a), (1b), ...
\begin{document}
\begin{exe}
\ex \label{ex:one} A top-level example.
\begin{xlist}
\ex \label{ex:sub} A sub-example.
\end{xlist}
\end{exe}
See \cref{ex:one} and \cref{ex:sub}. % -> "example 1 and example 1a"
\end{document}expex 的引用机制——\getref、\getfullref、\nextx
在 expex 里,标签不用 \label,而是写在例句紧后的尖括号里——\pex<top>,子例则是 \a<one>。引用用 \getref{top} 得到 1;子例要带上父级前缀,\getref{top.one} 得到 a;而 \getfullref{top.two} 得到 1b,即把上层编号与子标号合在一起的形式。前向引用还有 \nextx(下一个例句的编号)与 \lastx(前一个例句的编号),于是「见下面的 (1)」可以不写具体数字。当引用无法解析时,输出里会印出带方括号的 [one],日志中出现 ====> EXPEX WARNING: tag one is called but not defined.——就不让未定义的引用悄悄溜过这一点而言,它比 cleveref 的组合更安全。
\documentclass{article}
\usepackage{expex} % lives in tex/generic: works under plain TeX too
\begin{document}
Consider (\nextx). % forward reference to the example below
\pex<top>
\a<one> \begingl
\gla Kore wa rei desu.//
\glb this TOP example COP//
\glft `This is an example.'//
\endgl
\a<two> A second sub-example.
\xe
% \getref{top} -> 1 \getref{top.one} -> a \getfullref{top.two} -> 1b
See (\getref{top}), (\getref{top.one}) and (\getfullref{top.two}).
\end{document}expex 出自约翰·弗兰普顿(东北大学)之手;README 的版权年份为 2006–2017,随附版本为 v5.1b,用户指南长达 82 页。技术上有意思的是它所在的位置:tex/generic/expex/。也就是说,它不是 LaTeX 专用,而是在 plain TeX 下也能运行的宏集,expex.sty 只是一层薄薄的 LaTeX 包装。注释的写法也和 gb4e 不同:在 \begingl … \endgl 中排列 \gla(原始数据)、\glb(逐词注释)、\glft(自由译文),而每行以 // 结束,不是 \\。这个 // 正是初次接触 expex 的人最先弄错的地方。
Language Science Press 的工具组——langsci-gb4e 与 langsci-avm
当下语言学 LaTeX 生态中更新最勤的一角,是开放获取的语言学专业出版社 Language Science Press 发布的那一组宏包。langsci-gb4e.sty(日期 2022-10-21)是经过整理的 gb4e,并把 cgloss 与 jambox 的功能一并纳入。文件放在 tex/xelatex/langsci/,但 kpsewhich 不论引擎都能找到,实测在 pdfLaTeX 与 XeLaTeX 下都能无错通过。同一目录里还有 langscibook.cls——出版社用来排自家图书的那个真正的类。一家把书免费公开的出版社,连排出这些书的排版类也一并放上 CTAN,于是作者能在自己机器上做出与出版社相同的 PDF。
关于特征结构(属性值矩阵),要注意旧文章点名的 Chris Manning 的 avm 宏包并不在 TeX Live 2024 里。写 \usepackage{avm} 会停在 ! LaTeX Error: File 'avm.sty' not found.。取而代之的是 langsci-avm(Felix Kopecky,v0.3.0,2023 年 2 月 21 日),其 README 明说它「与 Christopher Manning 的 avm 宏包服务于同一目的,但不共享任何代码」。它的写法是命令而非环境:\avm{ [ cat & [ head & noun \\ case & nom ] ] },用 & 分隔属性与值,用 \\ 分隔行。方括号、尖括号、圆括号、花括号各自会排出对应的括号。手册里有一节讲从 Manning 的 avm 迁移,手上有旧稿的话,从那里读起最省事。
如何排 IPA 音标——tipa、Unicode、tipauni 三选一
pdfLaTeX 就用 tipa,XeLaTeX / LuaLaTeX 就直接敲 Unicode,而 tipauni 是二者之间的桥。 tipa(福井玲 编写)用 ASCII 简写书写 IPA:\textipa{[tSi:z]},其中 S 是 ʃ、T 是 θ、N 是 ŋ、@ 是 ə、P 是 ʔ。记住这套映射是第一道门槛,但记住之后输入很快,而且只靠 pdfLaTeX 就能完成。若连续出现多处转写,可以用 IPA 环境整段包起来,不必反复写 \textipa{...}。若能用 XeLaTeX 或 LuaLaTeX,最直截了当的路子是用 fontspec 选一款含 IPA 的字体,在编辑器里直接敲 [tʃiːz]。TeX Live 2024 附带了 Linguistics Pro(linguisticspro),这是一套含 IPA 符号与声调符号的 OpenType 字族,所以不必额外安装就能走这条路。
不过,这两条路产出的 PDF 并不相同。用 pdftotext 从 tipa 排出的 PDF 中抽取文本,得到的是 [tSi:z]——是你输入的简写,而不是 IPA。用 pdffonts 查看,嵌入的字体是 TeX-tipa10 这个 Type 1 字体,编码为 Builtin;也就是说 PDF 的文本层不是 Unicode,读者复制或检索时都得不到 IPA。把同样的内容用 XeLaTeX 加 Linguistics Pro 排出来,pdftotext 返回的则是 [tʃiːz]、[θɔːt]、[sɪŋ]、[ma˥˥]。如果能设想审稿人会搜索某个音标,或者作者要从 PDF 里把自己的数据取回来,那么这个差别就不能耸耸肩带过。
于是 tipauni 就登场了(作者 निरंजन,v0.7a,2023 年 2 月 13 日,GPL v3+)。这是一个保留 TIPA 命令、却输出 Unicode 字符的宏包。把文档里的 \usepackage{tipa} 换成 \usepackage{tipauni} 再用 LuaLaTeX 编译,pdftotext 返回的就是 [tʃiːz], [θɔːt], [sɪŋ]。也就是说,二十年积攒的 \textipa{...} 不必重写,就能迁移到可检索的 PDF。它自带的示例假定使用 Charis SIL,但在没有该字体的机器上会退回 New Computer Modern,照样能用。作为 tipa 的兄弟,同一套里还有绘制元音四边形的 vowel(\putcvowel);用来排音系规则的 phonrule 也在 TeX Live 2024 中。
% Three routes to IPA, and what pdftotext gets back from each PDF.
% 1. pdfLaTeX + tipa -> text layer is the shorthand, not IPA: "[tSi:z]"
\usepackage{tipa}
\textipa{[tSi:z]} \textipa{[TO:t]} \textipa{[sIN]}
% 2. LuaLaTeX + tipauni -> same commands, Unicode output: "[tSiz]" becomes IPA
\usepackage{tipauni}
\textipa{[tSi:z]}
% 3. XeLaTeX/LuaLaTeX + fontspec -> type the IPA directly
\usepackage{fontspec}
\setmainfont{LinguisticsPro-Regular.otf}[
Path = /usr/local/texlive/2024/texmf-dist/fonts/opentype/public/linguisticspro/]
% then simply: [tʃiːz] [θɔːt] [sɪŋ] [ma˥˥]| 输入 | 引擎 | pdftotext 返回什么 |
|---|---|---|
tipa | pdfLaTeX | [tSi:z]——仍是简写;嵌入字体为 TeX-tipa10 |
tipauni | LuaLaTeX / XeLaTeX | [tʃiːz]——命令与 tipa 完全一样 |
fontspec | XeLaTeX / LuaLaTeX | [tʃiːz]——连 ˥˥ 这样的声调字也照样保留 |
优选论的 tableau——ot-tableau 与 *! 的位置
OT 的 tableau 由 ot-tableau 宏包提供,只需三个命令:输入、制约、候选。\inp{/pat/} 给出输入形式,一连串 \const{NoCoda} 把制约从左到右排开,每个候选写成 \cand{pa}{}{*}{}——候选形式后面跟着它对各制约的违反。最优候选用 \cand[\Optimal]{...} 标记,会得到那个指示手符号。致命违反直接写 *!,就照样印出来。要紧的是,制约的排序就是你书写 \const 的顺序,因此做重排序实验时,只需调换那几行 \const,而不必手工重排列。用 TeX Live 2024 附带版本编译 tableau 环境,没有报错。
\usepackage{ot-tableau}
...
\begin{tableau}{c|c|c}
\inp{/pat/}
\const{NoCoda}\const{Max}\const{Dep}
\cand[\Optimal]{pa}{}{*}{}
\cand{pat}{*!}{}{}
\cand{pati}{}{}{*!}
\end{tableau}要画句法树——forest 会无声地误读 qtree 的点记法
句法树在本站有专门的页面(「树形结构(forest / qtree)」),所以这里只记下迁移时才会咬人的一点。qtree 与 tikz-qtree 会在节点名前加一个句点——\Tree [.S [.NP ] [.VP ] ]——而 forest 的记法是 [S [NP] [VP]],不用句点。而把 qtree 的记法喂给 forest,不会报任何错:[.S [.NP Kim ]] 会被老老实实地排成一个名字就叫 .S 的节点。如果你得到一棵形状没错、但所有标签都以点开头的树,原因就在这里。完整的取舍比较以及 forest 的自动排布,请沿 related 前往。
最后,明确一下本页有意未涉及的内容。化学式与反应式(mhchem、chemfig)和兴趣、娱乐类排版各有专门页面。语言学这一侧留下的工具,还有选用 covington 与 linguex 时的写法、langsci-avm 面向 LFG 的语义括号(lfg 选项,需 XeLaTeX),以及用 glossaries 做术语表,但都不是主线。这个领域首先要定的,还是那句话——采用哪一套例句编号机制。若用 gb4e,一开始就把 \noautomath 与 \crefname 这三行写好;若用 expex,就习惯 \getref 的路数。等稿子超过一百个例句再换,代价比你想的要大。