寫書小記

我的書《Node.js開發指南》將要在7月10日左右出版上市,回想過去一年花費的心血,不禁感慨良多。藉此良機,我記錄了一下過去一年的些許經歷,向大家大致介紹一下這本書是如何誕生的。

我已經忘了是從什麼時候開始接觸到Node.js的了,大概是2009年末或2010年初吧,那時Node.js還不像現在這麼火,祗是剛剛誕生的衆多前途未卜的新技術框架之一。一言以蔽之,Node.js就是一個讓JavaScript運行在瀏覽器之外的東西。說起JavaScript,市場上JavaScript的書幾年前就已經氾濫了,許多書的一個共同特徵就是介紹以瀏覽器爲基礎的JavaScript,大多都是花很少篇幅介紹JavaScript語言本身,花大量篇幅放在DOM、BOM的分析或jQuery這樣的框架上。想想看這也是理所應當的,如果在當時不介紹瀏覽器中的開發,學習JavaScript有什麼用呢?

說起Node.js,它本質上並不是什麼新東西,服務端的JavaScript十幾年前就有了,異步程序設計也不是什麼新思路,祗是把它們結合起來放在服務器端,多少看來像一個異端。我呢,雖然對前端開發有所涉獵,但並不工於此道,偏偏我又對JavaScript這個語言有所偏好,Node.js簡直就是爲我量身定做的了。不知爲何,Node.js這個「異端」就這麼火起來了。2010年是Node.js飛速發展的一年,它從一開始的默默無聞突然間變得大紅大紫,這是我接觸之初都始料未及的。2011年它的發展更是迅猛,衆多巨頭都加入了支持,甚至連開源宿敵微軟都伸出了橄欖枝,這讓Node.js實現了真正的完全跨平臺。

任何一個新技術在誕生之初遇到的最大的障礙就是文檔的匱乏,這一點祗有喜歡嘗試的人纔有所體會。早期的Node.js文檔非常糟糕,沒有任何教程,也沒有成熟的「解決方案」供參考。遇到問題以後上Google搜索一般都是沒有答案的,能依靠的祗有去郵件列表詢問。詢問還不一定有結果,所以很多時候要閱讀源代碼。

2011年7月,我剛剛放暑假,想想閒來無事,不如寫一個Node.js的入門教程。想到便做,於是我打開當當網,在上面搜索了關鍵詞Node.js,期望能有什麼已經出版了的書以供參考,但沒有任何結果,影印版也沒有,這並不令我意外。我又上Amazon.com搜索,令我始料未及的是竟然纔祗有一個搜索結果,那便是當時還未上市的《Node Web Development》。在我的印象中,凡是在國內買不到的書在Amazon上肯定有英文版,但這次竟然Amazon也沒有!看來這個技術實在是太新了,導致市場上還沒什麼書。當下我的心中便萌生了一個大膽想法,我何不寫第一本書呢?

這個想法簡直太猖狂了!看看很多書的作者都是大學教授,或者產業界的領軍人物,有無數的經驗。而我呢,纔不過一個大二的學生,寫的書會有人看嗎?甚至連能不能出版都是個問題。此外我除了有一個維護了五年的博客以外,沒有任何寫作經驗,要寫一本書談何容易?也算是初生之犢不畏虎,我當時就決定大膽去嘗試了,反正大不了就放到網上大家看唄。儘管完全不知從何下手,但想起某些國外的書上作者寫着自己是用LaTeX寫成的,所以就從學LaTeX下手吧。於是我花了一個星期看各種LaTeX的入門資料,學會了編輯一些簡單的文檔,看了許多高人留下的宏包和模板,但LaTeX的繁複還是遠超我的預期,想排版出一本書真是太難了。挫敗感第一次擊敗了我,五分鐘熱度過了以後,我對寫書也提不起興趣了。後來我纔知道作者其實不用太關心排版的,出版社有專業的編輯,而且他們都用Word……不過我找到了更好的工具Sphinx,此後的整本書都是用它寫成的。

一放就是一個多月,當我再次提起興趣的時候,是我開始加入Accounts9的開發。之前雖然也用Node.js寫過不少好玩的東西,但都是自己折騰,這是第一次用Node.js開發真正要應用起來的東西。實際項目開發的過程中讓我學到了許多以前沒有注意到的細節,我對Node.js的興趣重新被點燃,於是我準備好好研究一下Node.js。我從Amazon花了幾十美元買了全世界惟一的一本關於Node.js的書《Node-Web-Development》,到貨以後便如飢似渴地讀完了所有的篇章。令我有些失望的是,這本書寫得並不怎麼樣,而且版本太老,Node.js在誕生之初的變化是極快的,許多API如過眼煙雲,換一個版本就改頭換面了。這畢竟也難以苛責作者,總要有人做先驅嘛。好在Node.js版本在0.6以後API已經趨於穩定,不會再「翻天覆地」了。靜言思之,我發現面對的是一片未經開墾的處女地,因爲祗要是第一本書,無論好壞總會有人買單。

冷靜下來,我決定先擬定一個提綱,然後就開始動筆。我花了一個月寫了兩章,分別是「Node.js簡介」和「JavaScript高級特性」,前者是一個對Node.js的綜述性介紹,而後者則是針對服務器端開發的需求講解JavaScript,與大多數圍繞瀏覽器介紹JavaScript的書有很大不同。寫了兩章以後,熱度再次減退了,因爲暑假已經結束,各種課業的壓力紛至沓來。儘管寫成一本書很有成就感,但遠水不解近渴,於是我又被擊敗了,寫書之事又擱置了下來。

有道是「無巧不成書」,世事偏偏就是那麼巧。有一次我和一個學姐(徐可可)一起吃飯,聊到她的家教工作,她說道她的一個學生家長是某個什麼出版社的。我一聽精神爲之一振,便向她介紹了我已經擱置了的寫書計劃。她聽完以後也挺感興趣的,答應幫我詢問具體出版事宜。後來得知,這位在出版社工作的學生家長竟然就是圖靈出版公司的總編謝工。圖靈出版公司啊,我仰慕已久,不知道讀過他們的多少好書(《C++ Primer》、《JavaScript高級程序設計》、《黑客與畫家》……)。通過她我與圖靈的另一位總編楊海玲取得了聯繫,並且在CNode社區的北京交流會上見面認識了。楊海玲也是IT出版界赫赫有名的人物,她在來到圖靈公司之前,她曾經是機械工業出版社下華章公司那一套黑皮的「計算機科學叢書」的出版負責人,像《算法導論》什麼的當年都是她翻譯引進的。我斗膽把寫好的兩章稿子和提綱交給了她,忐忑不安地期待評價。幾天以後,我得到了不錯的反饋,簡直像是給我注入了一針強心劑,我又有動力繼續創作了。

轉眼到了寒假,我開始把全部精力投入寫書當中,回到學校時我的書也完成了接近一半。但隨着寫作的進度深入,終於遇到了瓶頸——有些章節我實在不知道該怎麼寫。再加上又一學期開始了,我寫作的進程再次漸漸陷入了停滯。這次我清醒地認識到必須在找點激勵了,於是我找到圖靈,簽訂了出版協議。現在,有合同約定我要在4月1日之前交稿,我便不得不克服困難了。事實再次驗證,往往是期限即將到來的那幾天工作是最有動力的,我最終還是按照合同約定交稿了。寫作到後期時,我找了不少人幫助審稿,在審稿的過程中我發現原本自己認爲寫得不錯的地方還有很大改進的餘地。我比較嚮往的出版方式是持久地修訂,而不是一次性交稿,但限於目前的現實條件,這還做不到。

並不是說交稿以後就沒事了,我還要和編輯共同審教、排版,後期的排版過程中我又發現了一些錯誤。所以說,一個出版公司的好壞很大程度上看編輯後期是否認真,圖靈在這方面可以說是佼佼者。再到後來圖靈還幫我設計了幾個封面,最終我選中了下圖這個方案:

感謝對這本書提出寶貴意見的我的朋友們,他們是牟瞳、李垚周越鍾音蕭騏、楊旭東、孫嘉龍范澤一、宋文杰、續本達田勁鋒孟亞蘭和李宇亮。他們爲本書的結構、內容、語言表述等方面給出了許多有建設性的建議。感謝CNodeJS社區的賈超和田永強,微軟亞洲研究院的楊懋,以及VMware公司的柴可夫。他們不僅幫助審閱了本書,還解決了許多技術問題,給這本書提出了許多改進方案。還要感謝我的朋友徐可可、圖靈教育出版公司的楊海玲、謝工、王軍花以及其他各位編輯,他們給我提供了許多幫助和鼓舞,沒有他們的激勵,我很難頂着巨大的學業壓力堅持寫完這本書。

特別要感謝的是弓辰開發的Rime輸入法,我依靠它完成了本書的創作。本書寫作的時候是準確的傳統漢字,出版時按照版署要求轉換爲了簡化字(通過OpenCC)。

最後引書中的一段文字: 在過去JavaScript一直不被人重視,很大程度上是因爲它太低效了——不僅速度慢,還佔用大量内存。但如今Javascript的效率卻令人驚訝。歷史總是如此相似,正如沒有Shockley發明晶體管就沒有電子科技革命一樣,如果沒有2008年以來的JavaScript引擎革命,Node.js就不會這麼快地誕生。

2008年Mozilla Firefox的一次改動,使Firefox 3.0的JavaScript性能大幅提升,從而引發了JavaScript引擎之間的效率競賽。緊接着WebKit開發團隊宣告了Safari 4新的JavaScript引擎SquirrelFish(後來改名 Nitro)可以大幅度提升腳本執行速度。Google Chrome剛剛誕生就因它的JavaScript性能而備受稱讚,但隨着WebKit的Squirrelfish Extreme和Mozilla的TraceMonkey技術的出現,Chrome的JavaScript引擎速度被超越了,於是Chrome 2發佈時使用了更快速的V8引擎。V8一出場就以其一騎絕塵般的速度打敗了所有對手,一度成爲JavaScript引擎之王者。於是其他瀏覽器開發者的重新開始奮力追趕,與以往不同的是,Internet Explorer也加入了這次競賽,並取得了不俗的成績。

時至今日,各個JavaScript引擎的效率已經不相上下,通過不同引擎根據不同測試基準測得的結果各有千秋。更有趣的是,在不知不覺中JavaScript的效率已經超越了其他所有傳統的腳本語言,並帶動了解釋器的革新運動。JavaScript已經成爲了當今速度最快的腳本語言之一,昔日「醜小鴨」終於成了如今驚艷絕俗的白天鵝。

這是單獨介紹本書的頁面:Node.js開發指南

推薦一個神級輸入法——Rime

用了那麼多年的輸入法,一直沒有一個讓我滿意的。早年我是從 Windows 95 自帶的「全拼輸入法」開始使用的,印象最深刻的就是一次只能打一個字,還有完全不搭邊的聯想。後來 Windows 98 以後改用「智能 ABC」,相比全拼真是質的飛躍。現在輸入法中的看似平常的功能,如聲母簡拼、用戶詞庫、以詞定字、模糊音等等幾乎都發軔於「智能 ABC」。後來接觸到網絡以後,我學會了使用「拼音加加」和「紫光拼音」,這兩者除了詞庫大了不少以外與「智能 ABC」相比並沒有什麼飛躍。直到「搜狗拼音」的誕生,我纔對輸入法有了更深的理解。搜狗拼音應該是第一個把自然語言處理算法應用到輸入法中的產品,通過大規模的統計語言模型實現了「智能組句」功能,爾後被「Google 拼音」和「QQ 拼音」複製,不過都在同一水平。

我是一個對輸入法有特殊要求的人,因爲我要輸入繁體字。早期的拼音輸入法沒有一個支持繁體中文的,最早是「微軟拼音」率先支持了繁體,但它亂用異體字,真的是把「回」的四種寫法在不同詞中用全了。搜狗拼音和Google 拼音後來也支持了繁體,不過簡直太爛了,幾乎是基於字的轉換,完全不考慮簡繁一對多的情況。雖然現在支持了一些,但還是錯漏百出,用起來極其不舒服。我嘗試過使用註音輸入法,好處在於沒錯誤,而且支持聲調,但是太不靈活了,不支持簡拼和打長詞,因此我開發了 ibus-bopomofo 註音輸入法,試圖把拼音輸入法的一些好特性移植過去。另一個問題是臺灣的註音輸入法打出的字都是「臺灣正體」,最大問題是「着」「著」不分工,而且使用了「為」「裡」「台」等俗字。後來我乾脆轉到了形碼的陣營,先後學習了鄭碼、五筆和倉頡輸入法。可是當我習慣音碼以後,再轉到形碼絕非一日之功,雖然我一直練習,可打字速度還是達不到拼音的三分之一。難道普天之下就沒有一個能準確打出繁體的拼音輸入法嗎?

Rime

一直以來,這個答案是否定的,畢竟開發輸入法本來就是一件費力不討好的事,況且有這種需求的人又不多,有誰會去開發呢?一切還得靠自己。可惜我書到用時方恨少,讓我開發一個這麼複雜的輸入法可幹不了。直到不久前佛振的Rime終於誕生,我的願望纔成了現實。

Rime全名是「中州韻輸入法引擎」,它不僅僅是一個輸入法,而是一個輸入法算法框架。Rime的基礎架構十分精良,一套算法支持了拼音、雙拼、註音、五筆、倉頡等所有音碼和形碼輸入法,遠比基於碼表的各種「輸入法生成器」優秀許多。Rime默認提供了兩個拼音輸入法「朙月拼音」和「地球拼音」,兩者都可以輸入準確的繁體和簡體,而且「地球拼音」還支持聲調輸入。Rime還支持了許多種方言拼音,如吳語、粵語,甚至中古漢語。

更超出我預料的是,Rime還是跨平臺的!Rime針對Windows、Linux、Mac三大平臺提供了不同的發行版,核心算法不變,還能和系統完美融合,真乃絕妙。佛振還給Rime的發行版起了好聽的名字,Windows發行版叫做「小狼毫」,Mac發行版叫做「鼠鬚管」,Linux發行版叫做「中州韻」。

廢話少說,讓我們用截圖說話:

「幹」「干」「乾」涇渭分明。

「饑」和「飢」都不會錯哦。

「出」「齣」分工正確。

「才」「纔」不一樣。

帶聲調的「地球拼音」。

註音符號輸入法。

支持七萬Unicode漢字的倉頡,還帶提示。

粵語拼音。

吳語拼音。

簡化字也是可以用的(由 OpenCC 強力驅動)。

「臺灣正體」模式,滿足臺灣人的用字需求。

用完以後我真是對Rime佩服得五體投地了,真可謂神級輸入法!更多的簡繁一對多問題,歡迎大家嘗試這個表 https://github.com/BYVoid/OpenCC/blob/master/data/scheme/st_multi.txt

Rime 下載地址 http://code.google.com/p/rimeime/wiki/Downloads

順便給 360 殺毒使用者提個醒,由於該輸入法作者沒給 360 交保護費,被 360 殺毒某些版本列入「未知木馬」(還未知就叫木馬,恐嚇用戶啊),請使用者冷暖自知。

關於作者佛振

大概在兩年前,我開發 OpenCC 和 ibus-pinyin 的時候認識了 rime 的作者佛振。他是我認識的第一位輸入法開發專家,也是最令我佩服的一位。我曾經在 Ubuntu 10.10 Release Party 上與他有過一面之緣,當時爲之手寫註音符號的能力所震驚,至今自愧弗如。作者佛振不僅編程能力高超,而且對中文有很深厚的造詣,這樣的一個人開發了若干年的輸入法,豈有不好用之理?兩年以來,他始終以不變的熱情投入到開源輸入法開發的工作當中,纔發明出了這麼好用的一個輸入法。誠心向佛振致敬!

註:本文通過rime小狼毫「地球拼音」輸入方案錄入。

OpenCC網頁版發佈

經過一段時間的開發,OpenCC(開放中文轉換)網頁版( http://www.byvoid.com/application/opencc/ )終於問世了。這次發佈是真正意義上的OpenCC網頁版,成爲了一個Web 2.0應用,不再是以前一個簡陋的頁面。新版本的變化除了在於優美簡潔的頁面外,更提供了新的轉換選項,支持「簡體」、「繁體」、「簡繁混雜」,還支持異體字轉換,如「爲」「為」、「裏」「裡」等字,以兼容不同偏好的使用者。除此之外,OpenCC網頁版還集成了「地區用詞轉換」,這個本不屬於簡繁轉換,但與簡繁轉換相關性很强的功能。

不過OpenCC網頁版最大的兩點是提供了交互式校對的「精細轉換」功能:

使用「精細轉換」模式時,OpenCC將會把所有可能轉換不正確的部分標註,使用者通過點擊可以更換不同的轉換,以提高轉換的正確率。

OpenCC是開源軟件,以Apache Software License 2.0授權發佈,請大家支持。

中文詞彙地區差異比較——#1「晶體管」與「電晶體」

電子科技革命以降,大量新科技詞彙再次涌入中文。值得慶倖的是,中國仍然保留了其「能意譯則不音譯」的優秀傳統,沒有像日本一樣大量依賴片假名音譯,更不像越南一樣不翻譯而直接引入拼寫。令人遺憾的是,由於中國大陸和臺灣政治、文化、科技領域數十年的分裂,兩邊都各自建立了一套基本術語的翻譯體系,並且兩者相互不兼容。這種狀况一直到今天纔開始慢慢改善,然而嫌隙是不可能在短期內抹平的,更無法奢望中文翻譯的統一了。

由於OpenCC項目需要,我花了數月,終於整理出了一套中國大陸與臺灣之間的用詞差異(大量參考了維基百科)。這套用詞差異包括了IT類詞彙、人名地名和其他常用詞彙。值得强調的是,這僅僅是嚴格意義上詞彙的差異,不包括簡繁差異和異體字差異。爲了簡明起見,我統一用OpenCC標準的繁體描述。我已經將不少詞彙整理到了 https://github.com/BYVoid/OpenCC/blob/master/data/tw/tw-it.txt,左右兩列分別是大陸常用詞和臺灣常用詞。

本來我計劃寫一篇大而全的文章,對數百個詞彙進行一一辨析解說,但後來一想不如化整爲零,一個一個詞地精細比較,這樣相信可以質量更高,也加快了寫作和發佈。作爲第一篇,我就先從產生詞彙差異的一個「始作俑者」——電子術語開始吧。

1

晶體管 電晶體
二極管 二極體
三極管 三極體
晶閘管 閘流體
場效應管 場效電晶體

在電子元器件的翻譯中,大陸一律翻譯爲「XX管」,臺灣一律翻譯爲「XX體」。我曾經學習電子的時候,不理解「二極管」的「管」爲何物,因爲這是違背直覺的,我從來沒有在二極管中看到類似於「管道」的東西,而相應臺灣的譯名「二極體」就好理解不少。

二極體的英文是Diode,電晶體是Transistor,從名字上看都和「管」沒什麼關係,大陸爲什麼關係爲「管」呢?這要從「真空管(Vacuum Tube)」說起,「真空管」(又叫「電子管」)是名副其實的「管(Tube)」,而且它是電晶體在發明之前主要的電子元器件,最早的計算機就是用真空管搭建的。可以想像,電晶體發明之後,大陸沿用「電子管」的「管」作爲基礎翻譯了「晶體管」。

從辭源的角度來說,英文transistor一詞是transfer + resistor的縮寫,即「轉移電阻」,來自1948年的貝爾實驗室。儘管大陸和臺灣都沒有嚴格直接意譯爲「轉移電阻」,我還是認爲「電晶體」相較於「晶體管」更爲少產生誤解,因此支持臺灣的這一組翻譯。

OpenCC支持地區用詞轉換了

OpenCC剛剛發佈了0.3.0版本,這次發佈最大的變化是終於支持地區習慣用詞和異體字轉換了,這是之前一直被大家呼籲的功能。上個版本0.2.0發佈已經是一年前的事情了,這一年來花在OpenCC上面的時間屈指可數。其實我在半年前就發佈了一個用QT寫的OpenCC圖形界面,只是做得水平很一般,這次也修改了不少。

爲了展示地區轉換的效果,我隨便造了幾個句子: 原文:

鼠标里面的二极管坏了,导致光标分辨率降低。
我们在老挝服务器硬盘需要使用互联网算法软件解决异步的问题。
什么你在面睡
轉換到臺灣標準:
滑鼠裡面的二極體壞了,導致游標解析度降低。
我們在寮國伺服器硬碟需要使用網際網路演算法軟體解決非同步的問題。
什麼你在面睡

以上例子前兩個句子展示了地區用詞轉換,第三個句子是臺灣標準的異體字,如“為、床、裡、著”,OpenCC默認轉換的結果是“什麼你在面睡?”。

此次發佈新增了Mac版,和Windows版一樣都包含圖形界面:

至於libopencc和命令行,還是說一下怎麼使用吧,這次一下增加了10個默認配置文件,如下:

  • zhs2zhtw_p.ini
  • zhs2zhtw_v.ini
  • zhs2zhtw_vp.ini
  • zht2zhtw_p.ini
  • zht2zhtw_v.ini
  • zht2zhtw_vp.ini
  • zhtw2zhs.ini
  • zhtw2zht.ini
  • zhtw2zhcn_s.ini
  • zhtw2zhcn_t.ini

看起來貌似很嚇人,到底用哪個呢?我來分别解釋一下,首先,爲了保證轉換的準確性和異體字的統一,OpenCC引入了一種“能分則不和”的繁體作爲中間表示,任何轉換都要經過這個中間表示,而這個中間表示同時也是我所推崇的用字標準。同時區域轉換又分爲用字轉換和用詞轉換,即異體字(裡、裏)和地區習慣詞彙(服務器、伺服器)。這10個配置文件分别是不同的源頭和目標:

  • zhs2zhtw_p.ini 簡體到臺灣標準(只轉換詞彙)
  • zhs2zhtw_v.ini 簡體到臺灣標準(只轉換異體字)
  • zhs2zhtw_vp.ini 簡體到臺灣標準(轉換異體字和詞彙)
  • zht2zhtw_p.ini 繁體到臺灣標準(只轉換詞彙)
  • zht2zhtw_v.ini 繁體到臺灣標準(只轉換異體字)
  • zht2zhtw_vp.ini 繁體到臺灣標準(轉換異體字和詞彙)
  • zhtw2zhs.ini 臺灣標準到簡體(不轉換詞彙)
  • zhtw2zht.ini 臺灣標準到繁體(不轉換詞彙)
  • zhtw2zhcn_s.ini 臺灣標準到中國大陸標準(轉換詞彙,並轉換爲簡體)
  • zhtw2zhcn_t.ini 臺灣標準到中國大陸標準(轉換詞彙,保持繁體)

其中後綴p表示phrases,v表示variants,s表示simplified,t表示traditional。我們到底應該用哪個呢?多數情况下簡繁轉換只需用zhs2zht.ini即可,如果需要轉換臺灣常用詞彙,一般用zhs2zhtw_vp.ini;一般從臺灣繁體到簡體用zhtw2zhcn_s.ini,如果不需要轉換詞彙,用zht2zhs.ini。其他的配置依據需求使用,更複雜的情况,我們還可以自定義配置文件,參見說明。當然,如果你僅僅使用OpenCC的圖形版,完全沒有必要理會這些細節。

爲什麼要設計得看起來這麼複雜呢?目的是爲了適應各種不同的需求,例如很多時候轉換一片文章需要將其中的地區習慣用詞連帶轉換了,但在輸入法中就完全不能,否則就會干擾使用者的原意。更複雜的情形還有異體字的選擇等等。OpenCC創立之初的宗旨就是建造一個最好的簡繁轉換工具,而不是僅僅能用而已。

編碼自動識別工具 uchardet

最近在給OpenCC做圖形界面,遇到一個問題:OpenCC默認只能轉換utf-8文本,其他編碼像GB18030,BIG5只能轉換成utf-8以後,纔能用OpenCC轉換。這個問題說大不大,說小也不小。我完全可以增加一個選項,在打開的時候讓用戶選擇文本編碼,然後再轉換就行了,但這卻給用戶非常糟糕的體驗,因為很多非專業用戶根本不知道什麼是文本編碼,更別說辨別了。GB18030/BIG5硬要用utf-8打開的話,肯定會遇到亂碼。由於Windows默認是GB18030/BIG5編碼,一般情況下文本會被保存成默認編碼,這樣更大大增加了用戶遇到亂碼的概率。爲了提高體驗,我計劃實現文本編碼的自動檢測。

最早接觸到編碼是從做網站開始的,記得如果忘了在head中顯式地向瀏覽器指定編碼,就經常會出現亂碼,但亂碼也並不總是出現,這是怎麼回事呢?瀏覽器還是有自動識別的能力的。發現Firefox瀏覽器中有一個編碼選項,裏面有「自動檢測」,使用它絕大多數時候都能正確識別。

事實上純文本的編碼檢測是一個非常複雜的問題,甚至理論上根本不可能實現。確切地說,「檢測」應該叫「探測」或者「推測」纔更恰當。自動編碼探測的實現原理主要是統計學的方法,每個編碼會有一定的特徵,首先檢測特徵是否符合,再使用常用的匹配,類似於蒙特卡羅法。具體方法可以參考Mozilla

mozilla在很多年前就做了一個非常優秀的編碼檢測工具,叫chardet,後來有發佈了算法更加優秀的universalchardet,用於Firefox的自動編碼識別。我想,這麼出名的一個工具,應該肯定已經有不少人在用了。有意思的是,我在網上找到了chardet和universalchardet的各種移植:

惟一沒有的,竟然是C/C++的接口封裝。debian更是收錄了python-chardet和ruby-rchardet,卻沒有libchardet或者libuniversalchardet。莫非沒有C/C++的應用在使用chardet嗎?用強大的Google代碼搜索,發現的確有,但幾乎都是把chardet的代碼內嵌到了項目中,耦合十分緊密。更有直接調用python-chardet的,實現不夠純淨。

總覺不該是這樣,但經過反復確認,真的沒有一個獨立的universalchardet的C函數庫封裝。還是自己動手好了,我從mozilla上面取下來了代碼,做了一點點補丁,寫了一個接口和命令行界面,取名uchardet,大功告成。測試了一些GB18030和UTF8的文本,感覺準確率非常高,而且速度很快。但是當我試圖識別幾個字節的短文本的時候,卻出現了識別錯誤,開始以為是我的錯,後來發現我用Firefox直接打開,也是無法識別的,而且錯誤識別的編碼一樣。看來是上游的問題,應該是算法本身的缺陷吧。想想看,畢竟文本越短歧義的可能性越強。不過既然能達到和Firefox同樣的水平,一般應用也就够了。

項目主頁在Google code上:

http://code.google.com/p/uchardet/

代碼在github上:

https://github.com/BYVoid/uchardet

我爲什麽用universalchardet?其實編碼自動識別的解決方案不止一個,有icu提供的解決方案,IE也有API,還有已經在很多Linux發行版中的enca。我之所以用universalchardet,是因為它是最合適的。IE的API不能跨平臺,icu實現太龐大,enca是GPL(注意不是LGPL),使用它意味著我也要讓我的所有源碼使用GPL,而不是更加開放的Apache。universalchardet是MPL的,和LGPL差不多寬鬆,使用它是沒有問題的。我非常不喜歡以GPL發佈的函數庫,這給開發者的限制太大了。