如何評價 xeCJK?

今天查看 xeCJK 的手冊,發現大變樣。翻到後面的代碼實現,跟我以前看到過的 LaTeX 代碼完全不一樣啊。代碼總共有七千多行,我記得以前好像只有一千多行啊。為什麼會變化這麼大?


感謝邀請。本來沒打算回答什麼的,不過李清似乎把我抬得過高了,惶恐惶恐。

簡單地說,xeCJK 是一個在 XeTeX 引擎下處理中日韓文字斷行、標點調整、字體選擇的一個基礎性宏包。不過因為所有參與開發的都是中國人,所以只有中文處理,更確切一點說是簡體中文處理的機制是比較完全的,其他方面多少有些涉及,但肯定稱不上好。

關於 xeCJK @李清 已經說了不少,我做點補充。

xeCJK 的原作者是孫文昌老師,最早於 2007 年在論壇上發布:xeCJK for XeTeX。那個時候 XeTeX 引擎剛剛從 Mac OS 上移植到 Linux 和 Windows 並進入主流發行版(TeX Live 2007),由於對 Unicode 字元與 TrueType/OpenType 字體的直接支持,理所當然地受到關注,希望能把它用在實際的中文排版活動中去。

在排版東亞文字這一塊,XeTeX 這個引擎功能很好。直接支持 Unicode,所以輸入沒有問題,直接打漢字程序就能識別,不用再像以前 CJK 宏包那樣在宏展開階段還把漢字當成兩個或三個獨立位元組分別處理;直接支持讀取系統 TrueType/OpenType 字體,所以輸出也沒有問題,選定了系統安裝的中文字體就能顯示出漢字來,不用再像以前 CJK 宏包那樣先把一個 TrueType 中文字體用工具拆成 100 多個小字體,再從某個小字體中取出一個個漢字字元來用。這樣一來,以前 CJK 宏包、CCT 預處理器之類工具的最核心的工作——識別漢字字元、選擇漢字字體——就在底層迎刃而解了。而且 XeTeX 還通過調用庫的方式內置了斷行和禁則機制,因此大段的中文排版也沒有問題。可以說,什麼宏包都不用,用 XeTeX 也能直接排版看得過去的文檔了,這當然是巨大的優勢。

然而另一方面,XeTeX 仍留下一些問題沒有解決好:

  1. 中文(以及日韓)字體的所有全形字元都是相同大小的方塊,標點也不例外,一個逗號即使在方塊的左下角,右邊的間距也是不變的;而中文(及日韓)也不在標點後使用空格,傳統 TeX 對西文標點調整間距的 spacefactor 之類機制也通通失效。可在實際的排版中,標點壓縮,即縮小相鄰標點間距的功能卻是必不可少的。XeTeX 引擎沒有提供,就得由宏包在上層提供。
  2. 傳統上中文和西文混合排版,中文和西文的字體就是各自獨立的,進入計算機時代也是這樣。結果字體廠商發布的中文字體雖然也包括半形的西文字元,但基本上都不怎麼上心,設計師也不專業,字元形狀、間距等各方面都有問題,比不上單獨發布的西文字體好看。因此在實際的排版中,必須另外選擇與中文字體配套的西文字體,分別使用。但這樣做就需要在一段文字中反覆在兩種字體間切換,非常不便。
  3. 西文(和韓文)是按詞輸入的,詞之間用空格分開,TeX 把換行等同於空格,這樣一段文字中間就可以在詞間換行,便於防止出現過長的源文件行。但中文、日文是按字輸入的,字與字之間沒有空格,如果要把很長的源文件行斷開,就必須把多出來的空格去掉。如果在行末手工加註釋符 % 來去掉空格,就是自找麻煩。
  4. 中文和英文、公式等內容之間,應該有額外的間距分開。但很多人錄入時懶得用空格等方式把它們分開,就會擠在一起,非常難看。

而在 XeTeX 上構建的兩個幾乎同時期發布的宏包,xeCJK 與 zhspacing,就是為了利用 XeTeX 的優勢,同時解決這些問題而開發出來的。

xeCJK 與 zhspacing 的原理大體相同,都是利用了 XeTeX 的 XeTeXinterchartoks 機制。這是個什麼機制呢?XeTeX 給每個 Unicode 字元分配了一個類別,即 XeTeXcharclass,如西文字元是 0 類,漢字是 1 類,全形的左標點(左括弧、左引號等)是 2 類,全形的右標點(右括弧、逗號等)是 3 類,字元串的起點和終點邊界是 255 類,當然也可以自己給字元設定新的類別。這樣一來,XeTeX 處理文本中的字元時,就會不斷地從處理這個字元類別的狀態切換到處理下一個字元類別的狀態。XeTeX 允許你使用 XeTeXinterchartoks 命令來設定一些內容,在這個狀態轉移的過程中就把這些內容插入到你指定的兩類字元中間去。現在問題就簡單了:

  1. 標點壓縮就是在兩個標點類字元中間加一個負的 kern 字距;
  2. 中西文字體切換就是在漢字類與西文類的字元中間加一個字體命令,可能是 fontspec 的字體切換命令,也可能是更原始的字體命令;
  3. 空格消除就是在兩個漢字類的字元中間加一個 ignorespaces;
  4. 額外的間距就是在中文類與西文類中間加個 hskip 間距。

xeCJK 和 zhspacing 都是這樣做的,只是在具體細節上的處理有所不同。

李清提到的 xCJK、xCCT,則是只利用了 XeTeX 的字體選擇優勢,沒有充分利用 XeTeX 的 Unicode 支持優勢而產生的實驗產品。它們沒有使用前述的機制,而是與 CJK 使用的機制相似。

前面說了 XeTeX 相比舊的 TeX 引擎的優勢,以及 xeCJK 相比裸 XeTeX 的優勢。於是自 2007、2008 年以後大家對基於 XeTeX 引擎和 xeCJK 宏包的中文解決方案有那麼大的熱情,也就不足怪了。其時 CTeX 套裝自 2006 年底 2.4.6 版就再未繼續更新,於是就有人轉向支持 XeTeX 的其他系統,如基於 MiKTeX 的 MiCTeX 系統,如不基於 MiKTeX 的 MTeX 套裝,還有更多人開始使用 TeX Live 及其改造版 CTeXLive。一直到 2009 年吳凌雲再次更新 CTeX 套裝 2.7 版時,這股熱情都仍在。xeCJK 的發布帖,在那幾年也一直在 CTeX 論壇置頂。

那麼 xeCJK 相比同時期的宏包 zhspacing 又有什麼優勢呢?答案是積累。

CCT 是 20 世紀 90 年代初由中科院主導,由中科院計算所、化工冶金研究所、科技期刊編輯培訓部開發並向全科學院推廣的排版系統,又有中科院科技圖書情報出版委的贊助,工作量、開發強度、深度都是同時期和後來類似系統所難比的,因其使用廣泛,留下的遺產也多。孫文昌教授早年參與 CCT 的相關開發,CCTfntef 就是出自他手,對 CCT 的許多機制,如標點壓縮機制的理解也很深。後來 CJK 宏包廣泛使用,孫文昌教授開發了 CJKpunct 包,把 CCT 成熟的標點壓縮機制移植到了 CJK 機制上,又開發了 CJKfntef 包,把 CCTfntef 包的漢字修飾機制移植過來。——而 xeCJK,也正是繼承了從 CCT、CJK 一直以來的標點禁則、標點壓縮、NFSS 字體補丁等相關機制。所以在這些方面,特別是標點禁則與壓縮的處理上,就要成熟許多,效果也好。

公正地說,zhspacing 在處理狀態轉移時,代碼的質量是比早期 xeCJK 要高的,整個代碼更清晰,更容易維護;而舊版本的 xeCJK 則相對零亂,還有不少繼承自 CJK 的與核心功能無關的代碼。然而,xeCJK 的除了細節功能(標點、中西文間距等)更好,還具有與 CJK、CJKpunct 等宏包的兼容性。字體切換命令,CJKfamily;字距設置,CJKglue;標點格式設置,punctstyle;輸出一個漢字,CJKsymbol;輸出一個標點,CJKpunctsymbol——這些都與舊宏包保持一致。於是不僅使用舊的中文處理工具的人更容易遷移到新系統上來,開發者也方便得多。xeCJK 兼容 CJKfntef,兼容 CJKnumber,使用 CJK 的 ctex 等上層工具不需要花太多精力也就可以支持 xeCJK。這種兼容性有利於對舊有遺產的繼承,使 xeCJK 在早期更容易受到青睞。

xeCJK 於 2009 年進入 ctex-kit 項目由社區一起維護,孫文昌教授直到 2010 年還根據反饋修正一些 bug,不過那時主要由我向 ctex-kit 項目提交。在這之後因為孫老師精力所限,就完全交給社區維護了。李清接手重構之前,主要是我修改 bug,偶爾也增加一些功能。到 2012 年李清接手重構 xeCJK,則完全由 LaTeX3 的語法與工具進行了重寫,一方面因為語法原因長度增加了很多,一方面也增加了一些功能,清理了不少代碼——但基本原理還是前面說的那些,兼容性也基本保留著。xeCJK 3.x 具體的內容,可以看李清的回答。

xeCJK 前後的開發維護人員只有孫文昌、我、李清,功能上又大量繼承 CCT 以來的工作,所以主要是面向中國大陸地區的簡體中文橫排需求。於是這自然引出 xeCJK 的重要缺點:日文支持、韓文支持、標點在中間的繁體中文支持、直排支持等等,都非常少。雖然名號上有 C、J、K,但只有 C 是相對完整的。與之相對,xeCJK 在 2.x 時還是中英文雙語文檔的,李清重構 3.x 之後,就只剩下中文文檔了,這也令中國以外的用戶很難開始使用 xeCJK。

xeCJK 有一小部分功能的需求是來自國際社區和要求,如韓文要求的 CJKspace(spacing - How to write spaces between Korean words with XeCJK?),如生僻字處理的 fallback 功能(fonts - high and low CJK codepoints in a single XeLaTeX document),如異體字選擇(IVS)支持(Issue 116 -
ctex-kit -

xeCJK: Support for Ideographic Variation Selectors)等。

日本的八登崇之編寫了 ZXjatype 宏包,是基於 xeCJK 編寫的,在其中加入了一些符合日文排版習慣的命令與功能。這也是 xeCJK 在中文排版之外的一處使用。

那麼還有 LuaTeX 呢?LuaTeX 和 XeTeX 有些相近,但機制又有不同。LuaTeX 也具有直接支持 Unicode 和訪問系統 TrueType/OpenType 字體這兩大能力。在這方面與 XeTeX 是類似的,甚至還要弱一些:裸 LuaTeX 不能簡單地用 font 命令訪問字體(需要 luaotfload),也不能用類似 XeTeXlinebreaklocale 這樣的簡單命令允許中文斷行。不過,LuaTeX 的擴展機制比 XeTeX 更靈活,它允許在 TeX 排版演算法中間插入一段 Lua 語言寫的回調程序(callback),增強或是修改 TeX 的排版演算法,完成任何想要的功能。

於是乎,LuaTeX 的 CJK 解決方案的思路就是這樣的:字體選擇,用 Lua 語言定義一個虛擬字體,某一部分字元用西文字體,某一部分字元用中文字體;斷行支持,用 Lua 語言重寫 TeX 的斷行演算法,讓它在中文字元後正確斷行;標點壓縮,用 Lua 語言計算標點大小、位置,修改輸出過程,在輸出的時候把標點挪挪……總之,無論做什麼都可以用 Lua 語言寫一段代碼,或者增加某個功能,或者直接把原有 TeX 中的演算法替換掉,最後什麼都能實現。這樣的好處是,功能強,比 xeCJK 能利用的字元類別信息要廣泛得多,能力也強得多;但一個重要的壞處就是,把大量代碼用 Lua 腳本代替,排版一段文字就要執行上百次 Lua 回調函數,很慢很低效。而且由於 LuaTeX 提供的介面比較低級,開發難度也大一些。

中文社區曾經有一些 LuaTeX 中文支持的嘗試,不過和 LuaTeX 引擎本身一樣,主要集中於 ConTeXt 格式。日本的 LuaTeX-ja 出現並由李阿玲在國內推廣之後,大家也就不再開發面向 LaTeX 和 Plain TeX 的 LuaTeX 中文支持了,因為日本排版和中文排版很接近。與 xeCJK 植根於 CCT 的傳統類似,LuaTeX-ja 則深植於日本 pTeX 的傳統中,後者比國內 CCT 的開發更早也更深入,在一些功能上也有自己的特色。不過就通常實用而言,LuaTeX-ja 在 LaTeX 上的效果與 xeCJK 差別不大,速度可能更慢,習慣用法也有些差別。


這個標題太大了,還有點題不對文。 @Ch"enMeng 已經答得很好了,我都不知道該從何談起,就先簡單看看 xeCJK 的歷史好了。

xeCJK 的作者是南開大學的孫文昌老師。可以追溯到 2007 年,那時的 xeCJK 叫 xCJK,隨 CJK 宏包一起發布。xCJK 除了應用 fontspec 直接調用系統字體以外,沒有用到 XeTeX 的其他特性。對漢字的處理還是用 CJK 宏包的那一套機制,需要把漢字的首位元組設置為宏。與此對應的 xCCT 也是類似的處理。

改名成 xeCJK 後,應該就是開始使用 XeTeX 的字元類機制來處理漢字了,中西文間距的調整也更加合理。儘管如此,xeCJK 還是盡量兼容 CJK,代碼和處理方式很多繼承自 CJK 和 CCT。我從 2007 年開始接觸 LaTeX,最早中文處理用的是 CJK 宏包,直到 2009 年才開始轉向 xeCJK。所以對 xeCJK 的這段歷史不是很了解,歡迎 @劉海洋 和 @江疆 來補充。

從 TeX Live 2009 開始,LaTeX 下的中文支持有了很大的改善。xeCJK 的開發也趨於穩定,被收入 ctex-kit 項目,主要由劉海洋維護。

2012 年春天,我想給 xeCJK 擴展一些功能(多重備用字體和分區字體),就參與了 xeCJK 的維護。代碼也被我用 LaTeX3 語法重構了,其實最開始是想學習 LaTeX3 語法,拿 xeCJK 練手的。

現在回到問題內容。xeCJK 的核心功能的是:

  1. 中西文字體切換和間距處理。
  2. 中文標點符號壓縮。

xeCJK 3.x 和 2.x 版,在這兩個方面的原理是一致的,都是依賴 XeTeX 的字元類機制來完成。代碼膨脹這麼多,變化這麼大,一方面是因為新版本增加了不少功能,日常性的維護也要加入不少代碼。另一方面是由於新版本完全用 LaTeX3 語法重構過。LaTeX3 語法,嚴格按照規範寫起來,沒有傳統 TeX 語法那麼自由。LaTeX3 目前已經基本完成了編程框架,許多功能相當吸引人,比如展開控制那一部分簡直是神器。

至於如何評價 xeCJK,謝謝 @劉海洋 的邀請,這個問題其實由他來回答更合適。雖然目前 xeCJK 的代碼工作主要由我完成,但他在 xeCJK 維護中是項目監督一般的存在,學貫中西,觀點高屋建瓴,如甘露灑心,醍醐灌頂。我一個抱大腿的,書讀得也少,就來說說 xeCJK 的缺點吧。

  1. 雖然名為 xeCJK,但其實只是對中文(特別是簡體中文)支持較好。對日文、朝鮮文的支持不足,僅限於能看的程度。這個我缺乏相關知識背景和排版實踐,就無能為力了。
  2. 中文直排功能弱。雖然有過一些嘗試,但還有更多問題需要處理,比如直排標點壓縮的處理、基線的調整。

  3. 目前的用戶文檔更像是一個參考手冊,一些常用和高級的功能混合在一起,對新用戶不夠友好。沒有英文文檔,不便於國際交流。
  4. 難以和使用 XeTeX 字元類機制的其他宏包共用,比如 polyglossia 和比較有意思的 xesearch。
  5. 我沒有軟體工程方面的經驗,最開始的時候對 TeX 編程也知之甚少,xeCJK 的一些代碼可能寫得比較混亂,核心代碼沒有說明,不便於後來者維護。
  6. 比 @李阿玲 的 pTeX-ng 慢一個數量級,這個就不解釋了。


這個顯然不應該邀請我啊,具體細節我不懂啊……簡單說幾句好了……

功能方面

  • 內部載入 fontspec,藉助 XeTeX 的 font 原語直接調用系統字體

  • 通過劃分 Unicode 編碼範圍,接管所有 CJK 字元,使得所有 CJK 字元可以有和西文字元不同的設置

  • 做了 CJK 字元和相鄰西文字元之間的空距處理(大多數情況能正確處理)

  • 做了標點壓縮(通過 XeTeX 的原語 XeTeXglyphbouds 來獲取標點符號的寬度,然後分門別類,按照不同情況削減標點的空白距離)和禁則處理

總的來說,已經覆蓋了中文處理的基本內容。

技術方面

  • 選項方面用了 key - value 的形式,當然這個基本上是現代宏包的標配了

  • 宏包代碼用 LaTeX3 的語法構建,和未來的 LaTeX 接軌起來會比較輕鬆(ltx3 的語法看著暈,主要是命名規則比較的少見,texdoc expl3 看完第三節可能會習慣很多)

對比 CJK 的進步

CJK 是上一代的中文處理方式,其時有以下一些問題,在 xeCJK 里都不存在了:

  • GBK 編碼導致的「許蓋功」問題

  • 一個漢字拆成兩個「亂碼」,導致出錯信息完全不可讀

  • 字體安裝無比複雜(每次都要劃分字體、重新寫和字體相關的各種文件,然後 udpmap)
  • 中西文之間的空距處理得不好(需要作者手工在中西文之間添加一堆「帶子」什麼的)

和 LuaTeXja-fontspec 對比

這一部分你們應該邀請 @李阿玲 阿姨來補完……

相同之處

  • 都建立在 fontspec 之上

  • 都能直接調用系統字體

  • 選擇字體的語法都模仿 fontspec

不同之處

  • xeCJK 和 XeTeX 搭配使用;LuaTeXja-fontspec 和 LuaTeX 搭配使用

  • xeCJK 把
    mfamily sffamily 還有 tfamily 的 CJK 字元部分單獨拿出來處理,切換字族的時候中西文字體同時切換;LuaTeXja-fontspec 的思路則相反,另起爐灶新建了 mcfamily 和 gtfamily 兩個字族來處理 CJK 字元,與西文字元完全隔離開(兩種思路孰好孰壞純看個人習慣)

  • xeCJK 處理標點的思路是使用標點原本的寬度(最大可能寬度),然後削減合適的寬度;LuaTeXja-fontspec 的思路是先拿到標點實際的寬度(最小可能寬度),然後添加合適的寬度(兩種思路基本沒差)


推薦閱讀:

如何評價國內《守望先鋒》最強戰隊 MY 宣布轉項目?會有哪些影響?
如何評價董明珠被免去格力集團董事長,僅在格力電器任職?
如何評價CCTV4《海峽兩岸》主持人李紅的主持水平?
如何評價 The Band 沒有像披頭士那樣風靡中國?
如何評價敘利亞偷渡溺亡孩童照片為擺拍?

TAG:LaTeX | TeX | 如何看待評價X |