把纯拉丁文的文字敲进 LaTeX,出来的排版细致得出人意料:写 office,ffi 会熔成一个字形;AV 这一对收紧 1.11084 pt;换行位置是纵览整个段落之后选定的。可这套自动处理也留下了缺口——它会心安理得地把 wolffish 断成 wolff-ish。而如果你为了修正而用 \/ 打断连字,这个词的连字符断词又会彻底消失。本页连同实测数据,梳理排西文时作者必须自己拿的主意:何时打断连字、向 babel 声明什么、大写与小型大写怎么用,以及西文段落落进日文稿件里会发生什么变化。
LaTeX 会做的五个连字:ff fi fl ffi ffl
连字(ligature) 是把相邻的字母熔成一个字形,LaTeX 默认制作的是 ff、fi、fl、ffi、ffl 五个。正文里敲 office 或 fluffier 就会自动替换,源文件里不留任何记号。原因在于字形:f 右上的挑笔会撞上后面 i 的点或 l 的竖笔,因此从金属活字时代起就铸造 f 系连字。实测 T1 的 Computer Modern 10 pt,fi 连字宽 5.5542 pt,拆开的 f{}i 宽 5.83191 pt——连字窄 0.27771 pt,这个差值正是「为避免相撞而靠拢」省下的量。
同一套机制也作用于标点。连着两个连字符 -- 变成 en 破折号,用于数值区间;连着三个 --- 变成 em 破折号,用于插入语;两个反引号(重音符)与之后的两个撇号,则分别给出印刷体的左右双引号。这些转换烧在字体规格里,无需任何命令(破折号的选用另见「引号与破折号」页)。
打断连字的三种办法——只有一种保住连字符断词
一旦连字跨过语素边界——单词由部件拼成的接缝——它就不再帮忙,反而伤害可读性。典型例子是 shelfful(shelf + ful):熔掉 ff,两个部件的接缝就看不见了。这个词出自 Knuth 本人,见《The TeXbook》第 19 页,selnolig 宏包的说明书至今仍指明这一出处。cufflink、offload、wolffish、halflife 同属此类。传统上打断连字有三种办法:shelf\/ful(斜体修正)、shelf{}ful(空组)、shelf\kern0pt ful(零宽字距)。
这里有一处不量就看不出的差别。用 \showhyphens 查断点,原样的 wolffish 会被断成 wolff-ish(按语素本该是 wolf-fish)。wolf{}fish 同样断成 wolff-ish——连字没了,连字符断词却完好如初。可是 wolf\/fish 与 wolf\kern0pt fish 两者都一个断点也没有了,中间插 \mbox{} 也一样。道理很简单:\/ 与 \kern 各自插入一个排版节点,TeX 识别单词的扫描到此为止。而 {} 什么都不留下,单词依旧是单词——所以能在保住连字符断词的同时打断连字的,只有 {}。
| 写法 | 宽度(10pt, T1 CM) | showhyphens 的结果 |
|---|---|---|
shelfful | 30.88135 pt | shelf-ful — 保留连字,保留断点 |
shelf{}ful | 31.15906 pt | shelf-ful — 连字消失,断点仍在 |
shelf\kern0pt ful | 31.15906 pt | 无断点 — 连字符断词消失 |
shelf\/ful | 31.93665 pt | 无断点,另外还加上 f 的斜体修正 0.77759 pt |
实务结论是:要手动打断,就用 {}。 \/ 是《The TeXbook》示范的古法,从「补回 f 挑笔占用的空间」这一点上说也说得通,但它会让这个词在行末无法断开。短词危害不大;可像 selffulfilling 这样的长复合词一旦断点归零,那一行的词间就会撑开,整段看起来都变瘦。若能用 LuaLaTeX,selnolig 是最上乘的解:它把英语和德语的语素作为模式带在身上,能在正文不留任何记号的情况下抑制 shelfful 或 offload 中不需要的连字(TeX Live 2024 附带 0.302 版,仅限 LuaLaTeX)。
% \showhyphens output, TeX Live 2024, T1 Computer Modern:
% shelfful -> shelf-ful (ligature, break point kept)
% shelf{}ful -> shelf-ful (ligature broken, break point kept)
% shelf\kern0pt ful -> shelfful (no break points)
% shelf\/ful -> shelfful (no break points)
% wolffish -> wolff-ish (a break TeX gets wrong on its own)
A shelf{}ful of books, one cuff{}link, an off{}load.
% LuaLaTeX only: handles the whole word list for you
% \usepackage{selnolig}字距调整把 AV 收紧 1.11084 pt——而 {} 会把它一并抹掉
字距调整(kerning) 是对特定相邻字母对的间隙做收紧或放开的调整,使间距看起来均匀。像 AV、To、Wa、LT 这种字形带斜势的对,放着不管就会显得空。实测 T1 的 Computer Modern 10 pt,AV 为 13.8855 pt,中间夹一个 {} 的 A{}V 为 14.99634 pt——字体要求的那 1.11084 pt 收紧不见了。字距调整对照表存放在字体规格中(pdfLaTeX 一系是 .tfm 文件,OpenType 则是字体内部的表),TeX 读取它来决定字间。作者什么也不用写。
由此又反弹回上一节一条提醒:用 {} 打断连字,那个位置上的字距调整也会一并消失。若字体在两个 f 之间定义了字距,它也随之失去。shelf{}ful 的情形里,就是从连字的 30.88135 pt 变为 31.15906 pt——多出的 0.27771 pt 正是它。肉眼看不出来,但在标志、商标这类字面必须严丝合缝的场合,与其用 {},不如自己给 \kern 一个数值来得稳妥。反过来,要把整个词均匀地拉开字距(tracking / letterspacing)时,别自己撒 \kern,用 microtype 的 \textls{...},它不会破坏连字符断词。
连字符断词因语言而异——用 babel 声明语言
同样的拼写,断在哪里因语言而异。 用 \showhyphens 一查,signature 在英语模式下是 sig-na-ture,法语下是 si-gna-ture,西班牙语下是 sig-na-tu-re——断点位置本身就会挪动。Kongress 更极端:在英语模式下一个断点也找不到。人们抱怨的「行排不紧」「词间老是撑开」,相当一部分症状源自文档从未声明语言。\usepackage[french]{babel}(XeLaTeX、LuaLaTeX 则用 polyglossia)不是装饰,而是正确排版的前提。
| 单词 | english | french | ngerman | spanish |
|---|---|---|---|---|
signature | sig-na-ture | si-gna-ture | si-gna-ture | sig-na-tu-re |
Analyse | Anal-yse | Ana-lyse | Ana-ly-se | Analy-se |
Kongress | Kongress(无断点) | Kon-gress | Kon-gress | Kon-gress |
impossible | im-pos-si-ble | im-pos-sible | im-pos-si-ble | im-pos-si-ble |
transatlantique | transat-lan-tique | trans-at-lan-tique | trans-at-lan-ti-que | trans-atlan-ti-que |
即便声明了语言,自动判断在专有名词和术语上仍会失手。补救分三级。(1) 若希望某个词永远只在指定位置断开,就在导言区的 \hyphenation{...} 里列出它,用 - 标出允许的位置,词与词之间用空格分隔。在默认的(美式英语)模式下,manuscript 一个断点都没有,所以 \hyphenation{man-u-script} 几十年来一直是标准例子。(2) 只此一次,就在词中放 \-(任意连字符)——但带了 \- 的词从此只能在那里断开。(3) 完全不许断开,就用 \mbox{...} 包住。正如上文实测,\mbox{} 会剥夺所有断点,在这里恰恰正中下怀。
\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage[english]{babel} % loads the English hyphenation patterns
\hyphenation{man-u-script data-base FORTRAN} % global exceptions
\begin{document}
We rewrote the manuscript in \mbox{FORTRAN} overnight,
and the data\-base held.
\end{document}
% \showhyphens{...} prints the break points to the log --
% the fastest way to see what the current patterns actually do.babel 改的不只是断词,还有文字本身
把语言交给 babel,该语言的排版惯例也会一并生效。最直观的是法语。测量同一段输入 Bonjour: oui! 的宽度:不加 babel 是 58.48572 pt,加上 \usepackage[french]{babel} 变成 62.37366 pt——多了 3.88794 pt。从 PDF 抽出文字,原因一目了然:输出是 Bonjour : oui !。法语排版规定在高位标点(: ; ! ?)之前留一个空白,babel 替你插上了。写 \og ... \fg{} 还能得到书名号 « »。
德语通过引号简写给出下引号与上引号 „ … “,西班牙语、意大利语也同样带进各自的惯例。这里有一个陷阱:一旦切换 babel 的语言,空白就会出现在原先没有的位置,于是整套换行都变了,版面随之移动。「审稿返修途中加了语言选项,结果无关页面的图表全跑了位」这类事故正源于此。语言要在第一次写导言区时就定好,多语言文档则用 main= 明确指定主语言。
小型大写与大写——\textsc{UNESCO} 并不会变小
在西文正文里要让缩写或人名突出时,小型大写(small caps)比一串全大写更不扰乱行的灰度。命令是 \textsc{...},而这里有一个常见的误会。小型大写字体是「在小写字母的位置上放着缩小的大写字母」的字体。所以传给 \textsc 的必须是小写。实测 10 pt T1 的 Computer Modern,\textsc{unesco} 是 34.68042 pt,\textsc{UNESCO} 是 46.09985 pt——后者比普通的 UNESCO(42.35077 pt)还要大。本想缩小,结果成了三者中最宽的。
小型大写还有第二笔代价,在 PDF 这一侧。对排了 \textsc{unesco} 的 PDF 跑 pdftotext,取回来的是 unesco——仍是小写。字形是大写,文本层里却是小写字母。因此,把机构名或标准名排成小型大写的论文,别人按那个词检索时可能搜不到。若在意书目数据与可检索性,缩写就用普通大写来排,只在真正需要对比的地方才动用 \textsc。至于 \MakeUppercase,近年的内核能正确处理重音:\MakeUppercase{stra\ss e caf\'e na\"\i ve} 得到 STRASSE CAFÉ NAÏVE,其中 ß 按惯例展开为 SS。
还有一点:字体的库存是有限的。Computer Modern 没有斜体小型大写,所以写 \textit{\textsc{unesco}} 会得到 LaTeX Font Warning: Font shape T1/cmr/m/scit undefined,并悄悄改用倾斜(slanted)的小型大写代替。这只是警告不是错误,往往一路混到出版都没人发现。若确实需要斜体小型大写,就只能在换一款字体(Latin Modern 也在其中)与放弃这个组合之间二选一。
\textsc{unesco} % 34.68042pt -- real small caps
\textsc{UNESCO} % 46.09985pt -- full-size caps in the SC font
UNESCO % 42.35077pt -- ordinary capitals
% pdftotext of the first line gives "unesco", in lowercase
\MakeUppercase{stra\ss e caf\'e} % -> STRASSE CAFÉ
% English abbreviations keep the period, and the period is not a sentence end:
e.g.\ and i.e.\ and cf.\ and et al.\ -- see the punctuation page让右边距听话——microtype 与 Overfull hbox
把西文成品档次整体抬高的是 microtype 宏包。仅 \usepackage{microtype} 一行,就启用了两项微观排版。字符突出(protrusion) 把行末的标点以及 o、A 这类圆的、斜的字母略微推出页边,做出视觉上齐平的边缘。字体伸缩(expansion) 把每行的字宽伸缩百分之零点几,替字间胶分担一部分工作。可用的功能因引擎而异:microtype-xetex.def 里带着 Font expansion does not work with xetex 与 Letterspacing currently doesn't work with xetex 两条错误——所以在 XeLaTeX 下只能指望突出这一项。
即便如此,仍会有行冲出右边。日志里的 Overfull \hbox 就是信号。TeX 选择这些断行位置时,是把整个段落一次性权衡的——这就是 Knuth–Plass 算法,由 Donald Knuth 与 Michael Plass 于 1981 年发表在《Software: Practice and Experience》上。所以某行冲出,并不是算法在这一行上放弃了,而是整段没有找到更中意的排法。段落的松紧可用两条声明调节:\sloppy 宁可放宽词间也要避免冲出,\fussy(默认)则严守词间而任其冲出。只想放松一段,就用 sloppypar 环境包起来。但次序很重要:\sloppy 要留到最后。 先加 microtype,再改动一个词的措辞或补一个 \-——多数情况下就此收住,而且段落也更好看。
当日文作者来排一份西文文档
在日文环境里开始写英文论文,最先冒出来的通常是这条错误——! LaTeX Error: Unicode character (U+3000) not set up for use with LaTeX. 元凶是全角空格,输入法在转换途中留下的哪怕只有一个,也足以让 pdfLaTeX 停下。((U+FF08)和 )(U+FF09)同样会 not set up for use with LaTeX。麻烦之处在于,在编辑器屏幕上它们与半角空格、半角括号看不出区别。在动笔写英文稿的那天花上一分钟,把全角空格、全角括号、全角逗号搜出来清掉,此后就不会再被这类错误绊住。
还有一件事很关键:文档类与引擎的选择。用日文类(如 jsarticle)或 upLaTeX 来排英文文档,日文排版模型仍立在背后,插进西文并不需要的处理。若稿件纯为英文,老老实实转到 article 加 pdfLaTeX(或者用 fontspec 的 LuaLaTeX)最为稳妥。反过来,若以日文为主而夹杂西文,那些西文段落的句末间距容易参差,值得考虑 \frenchspacing(其机制详见「标点符号与括号」页)。另外,microtype 的突出与伸缩是为西文而设的;日文排版由 luatexja 之类以另一套模型承担。
- 开工第一天先清全角字符。 搜索全角空格 U+3000、全角括号
()、全角逗号并删掉。not set up for use with LaTeX讲的就是它们。 - 动笔之前先声明语言。 事后再加
\usepackage[english]{babel},换行会变,图表位置也跟着挪。 - 手动打断连字就用
{}。\/与\kern0pt会抹掉该词的连字符断词。用 LuaLaTeX 的话,交给selnolig。 - 缩写用普通大写排。
\textsc在 PDF 文本层留下的是小写,因此不适合你希望被检索到的词。 \sloppy是最后手段。 先microtype,再改措辞或加一个\-。Overfull \hbox留到那之后再数。