十二月 02
加入書籤 Google Bookmarks HemiDemi Del.icio.us MyShare Baidu Yahoo! My Web Digg technorati furl YouPush udn共享書籤 Fiigo網路分享書籤

越來越多資訊包含了多種語言,以往單純的 Big5 文件已經無法處理,所以大家漸漸傾向把文件輸出成 unicode 型式。然而,Unicode 不像 Big5 只是單純的雙位元字集,佔用固定的 code range 那樣單純,它的複雜度更高。

在尋找適合的 solutions 時,發現以 Java, C 此類語言的資源較為豐富,而 php 則是要到 php 6 之後才會內建,而且要編譯 International Components for Unicode 的相關模組。而現在大家慣用的 iconv 指令,卻無法在 unicode 的編碼方式作切換。(會的人麻煩 comment 指點一下喔,謝謝!)

花了一點時間爬文後,整理出以下的最簡方案:

  • Unicode 轉 UTF-8
    首先,檢查檔案是否包含 Unicode BOM 標頭(\xFF\xFE)。
    然後,兩兩取出字節,轉換成 binary string。
    轉換過程中,利用 $cache 雜湊表來節省不必要的運算;而 ASCII 區段的文字則另外經過 iconv 的轉換以相容部份特殊符號。(以下字碼轉換的程式參考自 CentralNic Unicode Library,但修正了原碼中對 $dec < 128 的設定,將之擴大為 256 以改善其特殊符號不相容的問題。)
    程式碼如下:
    $cache = array() ;
    $text = preg_replace("/^\\xFF\\xFE/","",$text) ;
    for ($i = 0 ; $i < strlen($text) ;) {
         $dec = ord(substr($text,$i + 1,1)) * 256 + ord(substr($text,$i,1)) ;
         $i += 2 ;
         if (!array_key_exists($dec,$cache)) {
              if ($dec < 256) $cache[$dec] = iconv('ISO-8859-1','UTF-8',chr($dec)) ;
              else if ($dec < 2048) $cache[$dec] = chr(192 + (($dec - ($dec % 64)) / 64)) . chr(128 + ($dec % 64)) ;
              else $cache[$dec] = chr(224 + (($dec - ($dec % 4096)) / 4096)) . chr(128 + ((($dec % 4096) - ($dec % 64)) / 64)) . chr(128 + ($dec % 64)) ;
         }
         $string .= $cache[$dec] ;
    }
    return $string ;