星期四, 8月 24, 2006

用 PHP 處理中文

用電腦處理中文,經常是件瑣碎又麻煩的事。

先前(例如,談古契書資料處理:之一)曾經提過,光是中文編碼,就有可能讓程式設計者忙昏頭又倍感沮喪。PHP 有一個「也算是令人感到麻煩」的地方,就是它的系統是被假設在 ISO-8859-1 編碼下運作的。

另一方面,現在「比較先進」的系統架構或程式語言,內部的編碼似乎都傾向於使用 Unicode(通常是 UTF-16,至於是大印地安 Big Endian 或者小印地安 Little Endian,則似乎還是涇渭分明,各有擁護者)。或許,有相當大的一部份原因,就是希望能夠減少程式的開發與維護時,處理各種編碼轉換的複雜性吧。

那麼,要用 PHP 來處理中文,該怎麼做呢?我想,程式設計者只能自己處理編碼的問題了。

好在 PHP 有提供轉碼的函式,使用上還算方便。一般來說,採用 UTF-16 或者 UTF-8 來處理字串,應該都是可行的。例如,假設我們的輸入與輸出字串都是以 BIG-5 的方式編碼,但是想要用 regular expression 找出字串中符合樣式的子字串,那該怎麼做呢?以下是一種方法:
<?php
mb_internal_encoding('UTF-16LE');
mb_regex_encoding('UTF-16LE');

function mb_utf16($s) {
return iconv('BIG-5', 'UTF-16LE', $s);
}

function utf16_to_big5($s) {
return iconv('UTF-16LE', 'BIG-5', $s);
}

$s = "雖然感覺上像是藉口,但實際上感覺的東西,很難說清楚。";
mb_ereg_search_init(mb_utf16($s), mb_utf16('感覺|藉口'));
while ($match = mb_ereg_search_regs()) {
print utf16_to_big5($match[0]) . "\n";
}
?>
它可以成功地比對出三個子字串:「感覺」、「藉口」、「感覺」。當然啦,如果要進行字串的取代,PHP 也提供了 mb_ereg_replace() 這樣的函式。

「麻煩囉唆」的地方,就在於必須反覆地呼叫 mb_utf16()utf16_to_big5() 這類函式,這讓程式(至少看起來)一下子變得複雜許多。只是,相較於物件導向的程式語言,經常需要建立一堆物件來處理(正規表達式的字串比對),我還是覺得 PHP 在使用上比較簡單些。

另外,值得一提的是,要在網路上找到使用 mb_ereg_serach_init()mb_ereg_search_regs() 的範例程式,竟然比想像中來得困難許多。因為不知道合適的查詢字串長得什麼樣貌,我只能混用這幾個關鍵字,加上 example、source code 之類的字彙來查詢。然而,用 Google 搜尋的結果,找到的幾乎都是 PHP manual 的內容 --- 而很不幸的是,目前 PHP manual 沒有列出使用的範例。

這或許也是搜尋引擎的限制:當多數網頁都含有「並非使用者想要」的類似內容,而搜尋引擎又認為這些網頁是「相關網頁」時,很容易讓使用者感到挫折。通常,解決的方式是將問題推給使用者,希望使用者能夠自己找到更合適的查詢字串。但問題是:使用者該怎樣做,才能找到合適的查詢字串呢?

5 則留言:

lcat 提到...

這種問題不是去 user group 或 forum 上找比較容易?

tu 提到...

應該是吧。

只是,這些年來搜尋引擎進步神速,就越來越少上 user group 或 forum 去找尋答案了...

匿名 提到...

嗨 杜老大好阿
我也為mb_ereg_search的例子所苦阿
找著找著就從google找到這裡了耶
在第二頁而已
果然是前人種樹後人乘涼阿

哈哈
感謝杜老大

LC 提到...

謝謝 好用的資訊 因為不常使用PHP處理中文問題
每次碰到問題 都要再搜尋一次相關函數 有幸能夠搜尋到並拜訪貴網誌 感恩感恩

tu 提到...

現在除了 Windows 系統外,用 UTF-8 編碼的應該比 UTF-16LE 來得多了。