【填坑】關於 LaTeX 的中文處理(長文慎入)

作者: ChenMeng0518 (LSiYue)   2014-03-27 01:14:06
首先要對板上的同好們說一聲抱歉。上次回答完問題之後﹐就消失了很長時間。一方面是
課業繁重﹔一方面是 TeX Live 2014 就要出來了﹐手頭幾個宏包急著更新(希望能隨
TeX Live 2014 發布)﹔一方面是手頭在修一本書﹐關於 GRE 考試的填空教程﹐工程
比較浩大﹐不過好在今天完成了它手稿的的四分之三﹔另外是最近自己身體欠佳﹐去了幾
次醫院。
雖然有諸多理由﹐不過還是要對大家說一聲抱歉。真的沒想到一拖就拖了這麼久。
今天來詳細說一說關於 TeX 處理中文字的一些事情﹐會比較長﹐希望大家做好心理準備。
下文中﹐一些術語的說法可能和台灣方面不大一樣﹐盡我所能總結如下﹕
macro 宏 巨集
package 宏包 巨集套件
file 文件 檔案
如果文章中有看不懂的術語﹐歡迎大家回復補充。
## 關於 TeX 系統的一點基礎知識
板上同好們水平較高﹐所以分不清發行版、宏包、格式、引擎這些概念的應該是少數﹐不
過這篇文章之後也會在大陸的知乎網上發布﹐為了統一﹐所以一並講了吧。
TeX 家族是一個很龐大的概念﹐雖然 TeX 程序自己很小﹐龐大的原因﹐主要是後來人們
不斷地對它的功能進行擴展導致的。
TeX 家族最開始的概念是引擎。Knuth 老爹開發出的 TeX 是用 WEB 語言寫的﹐這是一
個文學編程的語言﹐需要用 Pascal 來編譯──不過現在的 Pascal 編譯器也是不能編
譯它的﹐版本不匹配──比較的繁瑣﹐效率也不夠高。於是有人開發出了 WEB2C 這個小
工具來將 WEB 語言的代碼轉成 C 語言﹐這樣能提高不少效率。
眾所周知﹐TeX 最開始是 Knuth 老爹為了自己的 TAOCP (不知道的請上網爬文)的排
版而創作的﹐所以當 Knuth 老爹自己對 TeX 滿意之後﹐就不樂意修改它了。然而盡管
TeX 是 Knuth 老爹和其他人(他的學生)一起做出來的東西﹐Knuth 老爹卻堅持隻有
自己才能修改名為 TeX 的東西。所以當 TeX 流傳開來之後﹐大家發現 TeX 功能上有
不如人意的地方的時候﹐隻能自己在 TeX 的基礎上做一些增強版。比如﹐著名的
e-TeX, 還有大家熟悉的 pdfTeX, XeTeX, LuaTeX 等。不是所有的擴展版都包含了
T, E, X 這三個字母﹐比如以前有一個引擎叫做 Omega, 它支持 16 種文字順序方向﹐
十分神奇。每一個 TeX 引擎都有一套自己的原語﹐不過所有的增強版引擎﹐幾乎都兼容
原始的 TeX 的原語──語法一致﹐但功能可能變強大了。
這些增強版﹐包括最原始的 TeX 在內﹐都被稱為**引擎**。引擎是承擔最終排版工作的
可執行程序。
讓我們回到最開始的 TeX 上面來。眾所周知﹐TeX 是一個引擎﹐同時也是一種宏編程語
言的名字。Knuth 老爹的原始版 TeX 一共有三百多個最原始的宏﹐我們把它們叫做
TeX 原語(TeX primitive)。其他所有的宏都是通過他們構建出來的﹐所以從理論上
說﹐隻要掌握了這三百多個原語﹐就能讓 TeX 幫我們解決一切問題了。不過最原始的東
西往往是強大的﹐但同時是不方便使用的。為了方便使用﹐我們就要在這些原語的基礎上
為常用的功能編寫宏。
有一些宏非常常用﹐所以如果每次都載入這些宏會繁瑣且緩慢。所以 Knuth 老爹允許人
們將常用的宏編譯成為格式(format, 擴展名為 fmt)。Knuth 老爹自己設計了一個格
式﹐稱為 plain TeX, 加上原語﹐他一共有 900 多個命令。因為它太基礎﹐用得非常
頻繁﹐所以大多數時候人們講到 TeX 語言的時候﹐指的是 plain TeX 構成的那些指令
集合﹐而不是 TeX primitives.
TeX 是面向排版的﹐所以許多命令晦澀難懂──通常寫文章的作者不需要知道這些細節﹐
於是﹐剛剛獲得圖靈獎的 Leslie Lamport 博士在 plain TeX 的基礎上又編寫了一些
宏﹐並編譯為格式﹐取名為 LaTeX. La 就是他姓氏的頭兩個字母﹐仿照中國古代的叫法
這就是所謂的萊氏 TeX. 所以你看﹐不管是中國人還是外國人﹐都想著光宗耀祖呢。
LaTeX 優秀之處在於﹐它將內容與格式分開﹐使得作者不需要﹐或者隻需要知道很少的排
版細節就能排出漂亮的文章。
除掉 plain TeX 和 LaTeX, 常見的格式可能就隻有 ConTeXt 了。
在格式的基礎上﹐人們發現實現某一些特定的功能的時候﹐使用的宏命令總是一樣的。所
以如果把它們打包起來﹐就會變得很方便。所以出現了宏包(package)這個東西。宏包
總是和格式對應﹐LaTeX 格式的宏包往往不能用於使用 plain TeX 格式書寫的文章之
中。LaTeX 中最常用的幾個宏包可能是﹕amsmath, geometry, hyperref, xcolor,
graphicx, booktabs 等。
除掉這些東西﹐人們還開發了一些輔助工具。比如﹐名為 BibTeX 的工具﹐就是用來生
成參考文獻的﹔名為 makeindex 的工具﹐就是用來生成索引的。另外對於引擎、格式、
宏包、工具﹐用戶要使用它必須有一份說明文檔來指引進步。所有這些東西﹐零零總總﹐
加起來有成千上萬個文件﹐如果讓用戶去一一下載安裝﹐一則不方便﹐二則不方便控制
版本。所以就有人/組織/公司將他們全部打包在一起。比較著名的發行版有 Windows
系統下的 MikTeX, 跨平台的 TeX Live, 為中文做過優化的 CTeX (大陸吳凌雲研究
員)﹐cwTeX (台灣吳聰敏教授)等。
至於 TeXworks, WinEdt, TeXstudio, TeXmaker 這些東西﹐隻是編輯代碼的工具﹐
和 TeX 系統並沒有直接的關系。
總的來說﹐引擎承擔排版工作﹐對應一套原語﹔格式對應一套書寫規則﹔宏包對應一定
的功能﹔發行版則是所有東西的大雜燴。如果用汽車來做比喻﹐那麼發行版是整個汽車﹐
引擎是發動機和傳動系統﹐格式是方向盤、剎車、離合器這些控制系統﹐宏包則是音響、
車窗之類的各種功能的小物件。
## 說說字體
所謂排版﹐就是要把每一個東西擺在合適的區域﹐然後在這個區域上畫出特定的形狀。
理解了這個概念﹐我們就知道﹐不管是排版文字﹐還是排版圖形﹐所做的工作都是一樣
的﹐差別隻在於最終畫什麼。對於 TeX 來說﹐畫出什麼樣的形狀其實是不重要的﹐畢
竟這個形狀是給我們人類看的。所以 TeX 完全可以隻關注什麼區域放什麼﹐至於這些
東西長什麼樣﹐完全可以交給閱讀器去處理。
因此﹐我們可以很容易地想到﹐一個字體應該可以分成兩個部分﹕描述尺寸的和描述形
狀的。前一個部分我們稱之為 metrics, 後一個部分我們稱之為 glyph. 對於
METAFONT 生成的字體﹐確實就是有這兩個部分的﹐前一個部分擴展名是 tfm, 後一
個部分的擴展名是 pk. 不過並不是所有的字體格式都將兩個部分分開﹐比如
OpenType 字體﹐字符的尺寸信息和形狀信息全都保存在一個文件裡面。
在 TeX 原語中﹐調用字體的命令是 \font. 這個命令是後續各種字體調用命令的基礎﹐
包括 xeCJK 的 \setCJKmainfont 等命令﹐都是在它的基礎上建立起來的。
Knuth 老爹的 TeX 系統﹐限於當時的情況﹐隻支持自家的 METAFONT 生成的 tfm
文件。什麼意思呢﹖(Knuth) TeX 的原語 \font 隻認識 tfm 文件﹐別的什麼 ttf,
otf 統統不認識。這無疑是不方便的﹐畢竟現代優秀的字體大都是 ttf 或者 otf
格式。於是 XeTeX 應運而生﹐它的原語 \font 認識 ttf, otf 這些格式﹐所以能夠在
讀取安裝在系統上的這些格式的字體──隻要想辦法讓它能夠找到就行了。另一個支持
ttf, otf 字體的引擎是 LuaTeX, 不過繼承自 pdfTeX 的 LuaTeX, 它的 \font 命令
也不能直接讀取 ttf, otf 格式的字體文件﹐需要使用名為 callback 的庫來間接調用。
這也就是為什麼使用 LuaTeX 處理字體會比 XeTeX 慢的緣故了﹐雖然 LuaTeX 相較
XeTeX 有不少優勢﹐但是讀取字體這一塊﹐確實是比不上。
說完了單個字符﹐我們再來說說字符在字體裡邊的情況。
可以想象﹐字符在字體文件裡邊是按照某種順序排列在一起的。那麼﹐假設你就是 TeX,
你想要獲得 A 這個字符﹐你怎麼找到它在字體文件裡的位置呢﹖沒錯﹐A 的 ASCII 編碼
是 65, 如果字體文件是按照 ASCII 編碼的順序排列的﹐我們隻需要找到第 66 個(從 0
開始)字符就可以了。
遺憾的是﹐事情並沒有這麼簡單。一則編碼有許多種﹐字體裡不一定要使用某一種特定的編
碼﹔二則東亞文字有許許多多﹐各地區使用的編碼也不盡相同﹐必須協調好各部分之間的關
系。於是 LaTeX 規定了名為 NFSS (新字體選擇機制)的方案﹐字體屬性分成五個方面﹕
編碼(encoding)﹐比如 TeX text, TeX extended text;
字族(family)﹐比如 Roman, Typewriter;
字重(series)﹐比如 bold, narrow, medium;
字形(shape)﹐比如 Italic, Small Caps;
字號(size)﹐比如 10pt, 11pt.
明確了這些﹐你才能精確地說明白你到底需要哪一個字形﹐如何才能找到特定的字符。這些
東西你可能不熟悉﹐但是如果你用過一段時間的 LaTeX, 幾乎能說你肯定見過。LaTeX 的
關於溢出盒子的警告一般是這樣寫的﹕
Overfull \hbox (3.80855pt too wide) in paragraph at lines 314
作者: andrew43 (討厭有好心推文後刪文者)   2014-03-27 01:17:00
不推對不起自己!
作者: aufbu (programming)   2014-03-27 02:26:00
Great! Thank you!
作者: GirlInBlack ( 小蛋 )   2014-03-27 03:16:00
雖然我不寫中文paper還是要給大推!
作者: hyperino   2014-03-27 08:12:00
感謝原PO的用心
作者: kurt28   2014-03-27 11:34:00
推!!!!!
作者: traintrain (那)   2014-03-27 14:43:00
推!
作者: springman (司布林)   2014-03-27 20:45:00
謝謝,我收集起來了。
作者: LINGZ (肥兔小欽)   2014-03-28 11:53:00
不推對不起自己!
作者: uranusjr (←這人是超級笨蛋)   2014-03-29 22:52:00
毫無疑問的優文
作者: TassTW (為文載道尊於勢)   2014-03-30 11:31:00
作者: descent (「雄辯是銀,沉默是金」)   2014-03-30 14:14:00
厲害
作者: a29788685 (嘉峰)   2014-04-09 19:27:00
謝謝

Links booklink

Contact Us: admin [ a t ] ucptt.com