在使用 LaTeX 进行中文文档的撰写中,有一些中文的标点符号用普通输入法输入非常麻烦,比如,知乎 风格的直角引号 「 」 『 』
(U+300C
~U+300F
),科技文献特别是数学文献中为了避免与下标 0
、o
混淆而使用的实心句号 .
(U+FF0E
),以及书名中再次使用书名的单书名号 〈 〉
(U+3008
、U+3009
),党政机关公文文号中使用的六角形括号〔 〕
(U+3014
、U+3015
)等等。有些符号尚可以在 LaTeX 中利用相近符号替代,比如 .
可以直接使用西文的 .
,〈 〉
则使用西文的 < >
或使用数学公式中的尖括号 \langle \rangle
(这两个符号长这样:)等替代,但这些替代方案的字形(glyph)及其与其他字符之间的字偶间距都是不合适,实际上是一种错误的表达方法,就好像用 x 来表示 ,用“日”字来表示“曰”字 一样。当然,这些符号都有对应的 Unicode 编码,不过,使用 \symbol
+ Unicode 编码可不是一种合适的解决方案,毕竟,谁脑子里能记得住这么多Unicode 编码呢? xeCJK
宏包为字体设置提供了 Mapping
选项,在一定程度上可以解决这些问题。本文简单介绍一下实现方法。
xeCJK
提供的映射
xeCJK
提供了四个 TECKit 映射文件,可以在设置字体的时候通过 Mapping
选项来使用它们。分别是:
fullwidth-stop
将字体的空心句号。
映射成为实心句点.
full-stop
将字体的实心句点.
映射为空心句号。
han-simp
将字体中的繁体中文字符映射为简体中文字符。han-trad
将字体中的简体中文字符映射为繁体中文字符。
后两个文字字符映射需要注意,这里只是字符机械一一映射,在汉字简化过程中,有很多字进行了合并,如“后”和“後”统一简化成“后”,“鐘”和“鍾”统一简化成“钟”,在使用 Mapping=han-trad
选项后不会根据上下文将“后来”改为“後来”,“闹钟”将被改成“鬧鍾”而不是正确的“鬧鐘”,不过这比 Microsoft Word 把“菠萝”改成“鳳梨”,“海内存知己”改成“海記憶體知己”要强得多了……
闲话不多说,切入正题。Mapping=fullwidth-stop
实际上就是实现科技文献中使用实心句点 .
的方法,只要给正文 CJK
字体加上这一字体特性选项,在书写源文档时使用正常的句号 。
,编译后就会将 。
映射为 .
输出。简单一个 MWE 如下:
1 | \documentclass{ctexart} |
效果如下:
xeCJK
宏包是通过 TECKit 生成的映射文件实现这一功能的,我们在路径 %texmf%/fonts/misc/xetex/fontmapping/xeCJK/
下可以看到对应四个选项的 *.map
文件和 *.tec
文件。其中,宏包需要调用 *.tec
文件,这个文件由 TECKit 编译对应的 *.map
文件而成。我们只需要制作自己的映射文件,放在 TDS 相应位置即可使用 xeCJK
进行调用。
TECKit 制作直角引号的映射文件
TECKit 是一个执行编码转换以供其他应用程序使用的小工具包。可以在官方网站下载页面下载。压缩包下载后解压在任意位置,进入系统架构对应文件夹,其中的 teckit-compile.exe
即为编译命令。
在这里不对 TECKit 进行详细的介绍(目前我只会照猫画虎,没有深研究这个程序,想介绍也没能力)。先复制 %texmf%/fonts/misc/xetex/fontmapping/xeCJK/fullwidth-stop.map
到这个目录,可以看一下 *.map
文件的内容为:
1 | ; TECkit mapping for conversion of `IDEOGRAPHIC FULL STOP" to `FULLWIDTH FULL STOP" |
源文件内容猜都很容易猜出来表达的是什么,;
显然是注释符(和 Lisp
有点像),LHSName
是说明左侧的符号类型,RHSName
是说明侧的符号类型,在 pass(Unicode)
之后,需要映射的字符 Unicode 编码之间用 <>
分隔,每一行定义一个字符即可。那么我们可以先把这个文件重命名为 raquot.map
,内容改为:
1 | ; TECkit mapping for conversion of `Qutation Mark" to `Right Angle Qutation Mark" |
保存文件后,在命令行运行:
1 | teckit_compile raquot.map -o raquot.tec |
文件夹内就编译生成了一个 raquot.tec
文件,我们将这个文件复制到本地 TDS 下(不建议放在系统 TDS 下,升级时恐怕就被删掉了),路径为:%texmf-local%/fonts/misc/xetex/fontmapping/xeCJK/
,然后以管理员身份在命令行中运行:
1 | texhash |
等命令运行完毕后,我们就可以在 LaTeX 文档中使用直角引号的映射了。现在把 MWE 改为:
1 | \documentclass{ctexart} |
编译文件后,文档中的 “ ”
就输出成为了 『 』
,效果为:
注意,映射文件的效果不能叠加,如果你既需要将 。
映射为 .
,又需要将 “ ”
映射为 『 』
,则需要重新创建一个映射方案,在 *.map
中将这些对应映射放在一起,重新编译一个 *.tec
使用。
其他映射的实现
同理,我们可以创建单书名号的映射方案 bookquot
,但是这种映射不能全文使用,毕竟单书名号只是用在篇名中引用书名的情况。这种映射通常只是用于宏命令的定义中,通过 xeCJK
宏包提供的 \addCJKfontfeatures
命令临时增加当前 CJK 字体的选项(对于 Mapping
选项只能是改变,Mapping
的多个方案是不支持叠加的)。例如,我在 Corp
宏集内曾定义了这样一个宏命令 \公文
来支持输出公文的标题、文号等。这个宏命令的定义是:
1 | \NewDocumentCommand\公文{s O{} O{} O{} m}{ |
这个命令带三个可选参数,一个必选参数,并提供了带 *
命令形式。必选参数是公文的标题,实际排印的时候,会将标题中的书名号映射为单书名号,并将公文标题放在一对书名号 《 》
之间,带 *
命令将省略发文文号,不带 *
的命令则将按可选参数提供的编号给出公文的文号。举例:
1 | \公文[沪水务][2019][1217]{上海市水务局关于印发《上海市排水检查井塑料防坠格板技术规程》的通知} |
效果如下:
其他映射字符和映射方法,你尽可以充分发挥自己的想象力去实现。Happy ing!