对 LaTeX 来说,句点不是「打一个点」的命令,而是改变随后空白宽度的命令。Dr. Smith 的空白是 3.33252pt,ends here. Next 的空白是 4.44336pt——键盘上敲的是同一个 .,在 10pt 文档里却差了 1.11084pt。而且判定的依据是句点前面的那个字符:小写字母表示句末,大写字母表示缩写。这一条规则,正是 NASA. Next 后面显得松散、Fig. 1 空得奇怪、e.g. 之后让人别扭的根源。本页讲清这套机制(\sfcode)、修正手段(\@、\ 、~、\frenchspacing)、省略号 \ldots 与 \dots 的分工、数字的千位分隔 \,,以及日文语境下句读与括号的取舍。
为什么句点后的空白会变宽——\sfcode 机制
因为每个字符都带有一个空格因子(space factor),当前一个字符留下的因子超过 2000 时,TeX 就会给随后的空白加上字体的「额外空白」\fontdimen7。在 10pt 的 article 里量:普通词间距 \fontdimen2 是 3.33252pt,额外空白是 1.11084pt,合计 4.44336pt——句末空白正好是词间距的 1.33 倍。在 \the\sfcode 后面接一个字符即可查看这些值,句点报出 3000。这个 3000 就是一切的起点。
| 字符 | 默认 sfcode | 对随后空白的影响 |
|---|---|---|
. ? ! | 3000 | 句末空白;10pt 时 +1.11084pt |
: | 2000 | 略宽的空白;正好卡在阈值上 |
; | 1500 | 仅伸缩余地略有变化 |
, | 1250 | 同上;绝不算作句末 |
) | 0 | 透明;原样传递前一个字符留下的值 |
A B C | 999 | 低于 1000,会抵消随后 . 的 3000 |
Dr. Smith 紧、ends here. Next 宽——大写字母的 sfcode 为何是 999
因为大写字母的 sfcode 是 999,也就是略低于 1000。TeX 的规则是:当前空格因子低于 1000 时,即便后面的字符带有大于 1000 的值,空格因子也只会升到 1000 为止。所以 A 后面跟 .(3000),实际留下的值是 1000,句末的额外空白不会出现。反之小写 a 正好是 1000,随后 . 的 3000 就原样通过。实测:A. a 为 18.60657pt,而写明空白的 A.\ a 完全相同,也是 18.60657pt。另一边 a. a 是 17.21802pt,声明 \frenchspacing 后缩到 16.10718pt。这 1.11084pt 的差,正是句末的额外空白。
这个设计不过是把 TeX 诞生年代英语排版的习惯照搬进来:当时句与句之间比词与词之间空得更宽。而为了不把缩写里的句点——Dr.、Ph.D.、Mr.——误认成句末,TeX 采用了一条一行的经验法则:「以大写字母结尾的就是缩写」。既然是经验法则,两边都会失手。NASA. Next 明明是句末却排得紧,Fig. 1 明明是缩写却排得宽。接下来的两节分别解决这两种情况。
用 \@ 告诉 LaTeX「这里就是句末」——NASA\@. Next
\@ 的意思是「把紧随其后的标点当作句末」,它要放在句点之前。写成 He joined NASA\@. Then he left.,大写 A 留下的 999 就被抵消,. 的 3000 得以通过。实测:A. a 是 18.60657pt,而 A\@. a 是 19.7174pt——相差 1.11083pt,正好是句末的额外空白。放错位置写成 NASA.\@ Next 则毫无作用。请记住:\@ 放在句点前面。这是一年只用上几次的工具:只在句子以首字母缩写(NASA、USA、DNA)或以大写字母收尾的专名结束时才需要。
缩写之后用 \ 或 ~——e.g. 与 Fig.~1
反方向的误判——以小写字母结尾的缩写被当成句末——通过把空白写成命令来解决。\ (反斜杠加空格)意为「在此放置一个普通词间距」,完全不看空格因子。实测:Fig. 1 是 26.5213pt,Fig.\ 1 是 25.41046pt,窄了 1.11084pt,正是正确的词间距。e.g.、i.e.、etc.、cf.、vs.、Fig.、Eq.、No. 都会掉进这个坑。
不过对于 Fig. 1 这类引用编号,~(波浪号)比 \ 更合适。~ 表示「与词间距同宽、且此处不得断行的空白」;实测 Fig.~1 与 Fig.\ 1 同为 25.41046pt。宽度相同,只是多了禁止断行。图表编号、公式编号、人名缩写若在行末被拆开会很难读,所以惯例写成 Fig.~\ref{fig:one}、Eq.~\eqref{eq:main}、D.~E.~Knuth。记住:引用编号用 ~,其他缩写用 \ ,就不会犹豫。
% a sentence really ending on a capital
He joined NASA\@. Then he left.
% abbreviations that must NOT get a sentence space
See, e.g.\ Knuth (1984); cf.\ the appendix.
% reference numbers: same width, but unbreakable
Fig.~\ref{fig:one} and Eq.~\eqref{eq:main}, after D.~E.~Knuth.\frenchspacing——几乎每份非英语文档都需要的一行
\frenchspacing 是一次性关闭句末额外空白的声明,在导言区写一行即可。它的内部简单得出奇:latex.ltx 中的定义只是把六个 sfcode 统一设为 1000,于是 .、?、!、:、;、, 全部按普通字符对待(默认的 \nonfrenchspacing 则恢复为 3000/3000/3000/2000/1500/1250)。实测:a. a 从 17.21802pt 缩到 16.10718pt,而 A. a 稳定在 18.60657pt 不变——本来就没有额外空白的地方,自然不受影响。
名字虽如此,这种紧排并非法语独有。法语、德语、西班牙语、意大利语以及英语之外的大多数语言,都不会让句与句之间比词与词之间更宽。 就连现代英语排版也大体转向了单倍间距。给 babel 传入语言通常会自动切换,但自己声明 \frenchspacing 更可靠。顺带一提,LaTeX 自身在 verbatim 环境内部就用了它——代码里 . 后面被拉宽可不好。保留还是取消句末宽空白,是应当在开工前与合著者约定的方针;中途更改会让差异蔓延到每一页。
\documentclass{article}
\usepackage[T1]{fontenc}
\frenchspacing % . ? ! : ; , all behave like ordinary letters
\begin{document}
This ends here. Next sentence starts with an ordinary space.
\end{document}省略号要用 \ldots 而不是 ...——以及 \ldots 与 \dots 的区别
连打三个句点的 ... 宽 8.3313pt,\ldots 宽 13.33008pt——相差 1.6 倍。... 的点挤成一团,看不出「省略」的意思;\ldots 则在点之间留出正确的空隙。所以正文中的省略号一定要用 \ldots 或 \dots。那这两者有何区别?在纯 LaTeX 里没有区别。latex.ltx 定义了 \dots 之后写下 \let\ldots\dots,二者字面上就是同一个命令;实测在文本模式下都是 13.33008pt,与 \textellipsis 完全一致。
差别只在加载了 amsmath、而且身处数学模式时才出现。amsmath 把二者分别重新定义:\ldots 恒为低位点,\dots 则成为向前预读、按上下文选择点的高度的命令。若是逗号序列就取低点(\dotsc);夹在二元运算符或关系符之间就取居中点(\dotsb,即 \cdots);积分用 \dotsi,乘法用 \dotsm。实际编译后用 pdftotext 抽取:$a+\dots+b$ 得到「a + · · · + b」,$a+\ldots+b$ 得到「a + . . . + b」——确实是不同的字符。不过在文本模式下两者都落到 \textellipsis,所以正文里不必纠结。
| 命令 | 输出 | 何时使用 |
|---|---|---|
\ldots | …(贴基线) | 正文中的省略号;数学中恒为低位点 |
\dots | 依上下文 | 在 amsmath 下按上下文选高度;数学中的首选 |
\cdots | ⋯(居中) | 夹在运算符之间,如 a+\cdots+b |
\vdots | ⋮(竖排) | 在矩阵或方程组中省略若干行 |
\ddots | ⋱(斜向) | 沿矩阵对角线的省略 |
\usepackage{amsmath}
% ...
He hesitated\ldots{} then went on.
\[
x_1, x_2, \dots, x_n \qquad a_1 + a_2 + \dots + a_n
\]
\[
\begin{pmatrix} a & \cdots & b \\ \vdots & \ddots & \vdots \end{pmatrix}
\]数字分位用 \,——用 1.6663pt 造出「1 000」
\, 是插入细空格(thin space)的命令,宽 1.6663pt,即 1 em 的六分之一。量一下 1\,000 得 21.66142pt,1000 是 19.99512pt——差值正好 1.6663pt。由于用逗号还是用点作千位分隔在各国正好相反(英语的 1,000 在德语里是 1.000),国际惯例长期推荐改用细空格分隔。\, 正是为此而设的空白。单位之前也用同一个命令,写作 5\,\mathrm{kg}。
不过随着位数增加,手工撒 \, 就不划算了。若稿件中数值与单位密集,交给 siunitx,写 \num{1000000}、\qty{5}{\kilogram} 更好——分位、单位前的空白,乃至负号的处理都会保持一致。请把 \, 看作「正文中偶然出现的某一个数值」的工具。
日文用「、。」还是「,.」——jsclasses 并没有切换选项
出什么符号取决于你在源码里敲什么,类选项无法切换。 jsarticle、jsbook 等 jsclasses 并没有把标点改成 ,.的选项。想用逗号句点,最直接的办法就是在正文里直接输入 ,.。这一流派本身源自规定标准文件样式的 JIS Z 8301——它在横排中使用「,」「.」——至今在数学书与理工科论文中仍很常见。另一方面,2022 年(令和 4 年)文化审议会建议《公用文写作方针》确定:读点原则上用「、」,横排时可视情况使用「,」。遵循投稿规定与所在领域的惯例,并在同一份文档内保持统一——判断标准仅此而已。
% comma-period style: just type the marks you want
\documentclass{ltjsarticle}
\begin{document}
本稿では,記法を次のように定める.まず,集合 $A$ を……
\end{document}日文括号 「」『』()——各自用在哪里
对话、引语与衬托词句用直角引号 「」;书名、作品名,以及嵌在 「」 内层的引用用双直角引号 『』。补充说明与读音用全角()。日文中请使用全角括号,不要混入西文半角 ():半角括号前后的留白规则不同,混一个进去,字面就会在行里明显浮起来。反过来,在西文(拉丁)引文内部则使用半角 ( )。
| 括号 | 名称 | 典型用途 |
|---|---|---|
「 」 | 直角引号 | 对话、引语、衬托词句;日文的首选引号 |
『 』 | 双直角引号 | 作品名,以及嵌在「」内部 |
( ) | 全角圆括号 | 补充、注记、注音 |
[ ] | 全角方括号 | 编者补充与标明的省略 |
【 】 | 方头括号 | 需要强烈突出的标题与条目名 |
〔 〕 | 六角括号 | 注记与补充;方括号的替代 |
至于日文约物究竟如何获得留白——JFM 中记录的字宽、连续右括号时的收紧、\inhibitxspcode、和欧文之间自动插入的 \xkanjiskip、行首行末禁则及其罚分——由「日语排版细节」一页负责。这里要记住的实务要点很简单:不要自己在约物前后敲空格。 敲了就会与引擎已经准备好的留白叠加,空出不自然的口子。
提交前搜索源码——一次性铲平标点的漂移
标点的偏差不会引发编译错误,只会在 PDF 上表现为一种别扭。所以最后做一次机械化的源码搜索最为可靠。合作写作时必然会出现这样的漂移:某一章按 \frenchspacing 的前提写、某一章 e.g. 后面留着裸空格、某一章在日文里混入半角括号。请对以下四项执行 grep。
- 缩写后的裸空格。 搜索
e.g.、i.e.、cf.、etc.、Fig.后面的空白,改为\或~(若已用\frenchspacing则无需)。 - 以大写结尾的句末。 搜索首字母缩写加
.(NASA.、USA.、DNA.),凡真是句末就插入\@。 - 省略号。 搜索连续三个句点
...,改成\ldots;在数学模式里交给amsmath的\dots。 - 日文中的半角括号。 搜索夹在日文行里的
(),改为全角 ( )。顺带检查约物前后是否被手工敲了空格。
# abbreviation followed by a bare space
grep -nE "(e\.g\.|i\.e\.|cf\.|etc\.|Fig\.) " *.tex
# a sentence that may end on an acronym
grep -nE "[A-Z]{2,}\." *.tex
# three typed periods instead of \ldots
grep -n "\.\.\." *.tex