我覺得 Intl.Segmenter 很好
前幾天看到 Tian-Yan 寫的〈文長慎入〉,說現在有些人明明只是很短的文章,卻說是「長文」。我想,文章到底算長還是短,確實很難有定論。
最近每次要寫部落格文章的時候,我都想著,這次沒什麼好說的,終於可以寫短一點了,然後又不知道為什麼越寫越長。不過等到好不容易整篇寫完的時候,又突然發現其實也才一千多字(之類的),根本就很短啊。直到現在,我還是不太確定這些文章到底算太長還是太短。
其實要知道一篇文章有多長真的不太容易。光是所謂的「字數」的定義就很有問題。我不知道一般人是怎麼算的。一般可以想到的問題可能有:是否包含標點符號?空格?換行?表情符號?中文以外的書寫系統該如何計算?例如一個英文字母是否算成一個字?還是應該把這些語言的詞(所謂的詞本身又有定義的問題)等同為中文的一個字(或幾個字)?合字(ligature)、合文是否算成一個字?還是分開算?
在電腦上,計算字數又有其他的問題。是否應該直接計算字串的長度?我說的是,在電腦上要處理文字,通常是把文字編碼成數字,然後儲存在一個清單中。在一般的程式語言中,如果你問電腦:「這個字串有多長?」他會告訴你這個清單上有多少個數字。但是依據編碼的不同,有的字在編碼的時候分配到的數字比較大,在這個清單上需要佔用好幾個數字的空間來表示,所以這組數字的長度常常不等同於我們認知上的文字長度。
還是應該計算字元的數量?所謂的字元就是編碼的時候制定的最小單位。一個字元在字串中可能是一個數字,也可能是好幾個數字,但是就算我們知道他是一個字元,也不一定就是我們想算的一個字。例如:「æ」在編碼上是一個字元,但是在概念上其實他是只不過是兩個字母連寫在一起?那該怎麼辦?有的時候看起來一樣的文字,在同一種編碼中也有不同的寫法,例如在 Unicode 中,像「é」這樣有變音符號的字母,變音符號與字母有分開編碼的,也有與其他字元加在一起之後編成一個字元的。
現在也有很多人,在網路上寫文章的時候,網頁上會顯示字數與估計的閱讀時間。因為這些文章不是純文字,所以計算上又多了新的問題。例如:如果文章的原稿是 Markdown,但是輸出成 HTML,他是要計算原稿的字數,還是輸出之後的字數?我說的還不只是不屬於真正的內文的格式的部份的長度。就算不考慮格式,像你如果在 Markdown 裡面打「--」,他輸出的時候會變「—」,這樣如果你的字數是包含標點的話,這要算一個還是兩個字?如果說到格式的話,甚至還有模糊地帶。例如如果你寫了一個清單,清單中的每個項目前面不是會有編號嗎?那這些編號到底要算在字數裡面,還是不算?
估算閱讀時間,也會讓字數計算的問題更明顯。通常的算法,都是直接把字數除以每分鐘閱讀的字數,例如假設一般人一分鐘可以讀五百字,就是把文章總字數除以五百,得到估計的閱讀時間。問題是,當你的中文文章裡面夾雜很多英文的時候,這個數字就不準了。英文一分鐘大概是兩百個單字,但是一個單字平均可能有六個字母。也就是說,一千個中文字的文章要讀兩分鐘,但是一千個英文字母的文章不用一分鐘就讀完了。
總而言之,這些種種問題,並沒有一個簡單的解決方法。當然,很多時候你只需要一個大略的數字,不需要太準確。但是如果你不知道這些看似微不足道的小問題的存在,最後可能會差之毫釐,失之千里。要認識這些問題,更重要的是,要了解計算字數的目的。例如有時候會看到有人說:「我們要限制一下標題的長度,不然空間可能會塞不下。」這聽起來很合理,但是如果你把他做成「標題不得超過三十個字元」的限制,你會發現,一樣是三十個字元,最後出現的長度卻會依據不同語言、字體產生很大的差異。或許你會說這只是一種簡便的作法,沒什麼大不了的,不過我總是忍不住覺得荒謬、不夠嚴謹。
如果你是看了這篇文章的標題,之後一路讀到這裡,你可能會發現已經寫了不知道多少字,竟然還沒寫到文章的主題。雖然這也不是什麼大不了的事就是了。其實這篇文章真正的主題是這個:當你在用電腦計算字數的時候,除了依循一般的慣例之外,例如別人用 Word,那你也用,免得其他人跟你的算法差太多(但是我沒有 Word。我也不知道怎麼辦),如果你是為了估算閱讀時間等等的目的,比較好的方式可能是用一個可以真正辨別字元、字數、甚至斷詞的程式。例如:如果你想計算中英夾雜的文章的閱讀時間,你可以假設一個中文詞與英文單字的閱讀時間是一樣的,這樣只要把中英文全部斷詞(而不是斷字),就能得到比較接近真實的結果。其中 Unicode 不只定義了文字的編碼,他還有所謂的 CLDR 資料庫,裡面有許多關於不同語言該如何斷字、排序等等的資料。如果你用的程式語言是 JavaScript 的話,他有一個很方便的內建的 CLDR 的介面,可以拿來分字斷詞,甚至他還會直接告訴你哪些「字」其實是標點符號,這個介面就是 Intl.Segmenter。