首頁 繪圖設計 工作閒聊 比賽活動 美術討論 標籤 圖片
BIG5 中文轉 UTF-8 中文資料庫轉換、檔案轉換工具
Type(Type) 2012/11/2 19:37 (Since 2012/10/30 14:56)

BIG5 轉 UTF8 萬國碼資料庫轉換、檔案轉換工具



分享幾個自己寫來轉 Vovo2000.com BIG-5/LATIN1 --> UTF-8 資料庫的工具,
基本上是用 PHP 5.3/5.4 的 MultiByte-String::mb_convert_encoding 相關功能來達成的。

環境前置作業: http://vovo2000.com/phpbb2/viewtopic-355829.html
如果你是使用 Windows 環境,
可能需要稍微對這個 script 小工具做一些小修改。


使用方式 / Usage:
代碼:

#
# 轉單一個 BIG5 大五碼檔案
#

$ /usr/bin/php big5_to_utf8_conv_xargs.php <ORIGINAL_BIG5_FILES>

#
# 配合 find 一次轉多個 BIG5 大五碼檔案
#
$ find . -name "*.htm" | xargs /usr/bin/php big5_to_utf8_conv_xargs.php



檔案轉好之後,檔名會變成 ".UTF-8" 如 a.htm --> a.htm.UTF-8
可用 rename 這個工具再把名稱改回來
代碼:

$ find . -name "*.htm.UTF-8" | /usr/bin/rename -f 's/\.UTF-8$//'


big5_to_utf8_conv_xargs.php (同時處理 "淚許蓋功餐" Back Slash)



big5_to_utf8_conv_xargs.php 有幾個選項可自行看你的需求修改

代碼:

$from_char = 'BIG-5';  // 來源編碼
$to_char = 'UTF-8';    // 對象編碼
$tmp_folder = '/tmp/'; // 暫存目錄
$encoding_detect_tool = '/usr/bin/file -b';
$big5_exception_all ==> 因為你一定已經處理過「BIG5::淚許蓋功餐」之類的字,所以轉完之後,你的資料可能會變成「功\夫,淚\眼」有 Back Slashes,要再一次轉回來;由於處理所有字元,太過於消耗時間,所以我只挑出常用字
$force ==> 強制轉,不做判斷(因為判斷也可能錯誤)


代碼:

<?PHP
/*
* php_big5_to_utf8_conv.php
*
* ------
* Usage:
* ------
* # /usr/bin/php php_big5_to_utf8_conv.php <FILENAME/SQL_DUMP>
*
* The output file will be ".UTF8" postfixed
* e.g.
*     mysqldb.sql --> mysqldb.sql.utf8
*
* ------
* Notes:
* ------
* => Convert BIG5 database or text/htm/php files to UTF-8 mainly;
*    it could be used to convert other encoding by touching $from_char or $to_char, in theory.
*
*    主要用來轉換中文 BIG5 --> UTF8,「理論上」也可以轉其他編碼。
*
*
* Rev: 0.1 ... service@vovo2000.com
*/

$from_char = 'BIG-5';
$to_char = 'UTF-8';
$tmp_folder = '/tmp/';
$encoding_detect_tool = '/usr/bin/file -b';

// 強制轉換
// $force = '--force';
$force = '';

for ($j=1; $j < count($argv); $j++)
{
    if (isset($argv[$j]) && file_exists($argv[$j]))
    {
        $filename = trim($argv[$j]);
        $tmpfile = $tmp_folder.time().'.txt';

        $cmd = "$encoding_detect_tool $filename > $tmpfile";
        // echo "Execute $cmd\n";
        exec($cmd);
        $orig_encoding = trim(file_get_contents($tmpfile));
        unlink($tmpfile);

        echo "Detect encoding: $filename => ".$orig_encoding."\n";

        // If you want to convert it anyway
   // $argv[2] == '--force';
      
        if (
             (strpos($orig_encoding, $to_char) === FALSE && strpos($orig_encoding, 'ASCII') === FALSE)
             || strpos($orig_encoding, 'extended-ASCII')
             || $force == '--force'
           )
        {
            $new_filename = $filename.'.'.$to_char;
            echo "Converting $filename --> $new_filename\n";
            $str = file_get_contents($filename);
            $new = mb_convert_encoding ($str, $to_char, $from_char);

            mb_internal_encoding($to_char);

            if ($from_char == 'BIG-5')
            {
                //
                // Hanlde 功\ 許\ 淚\ :: ie. You already workarounded with ADD_SLASHES in your database!
                //
                /*
                $big5_exception_all = '么功吒吭沔坼歿俞枯苒娉珮豹崤淚許廄琵跚愧稞鈾暝蓋墦穀閱璞餐縷擺黠孀踊髏躡';
                $big5_exception_all .= '尐佢汻岤垥柦胐娖涂罡偅惝牾莍傜揊焮茻鄃幋滜綅赨塿縷槙擺箤踊嫹髏潿蔌醆嬞獦';
                $big5_exception_all .= '佢螏餤燡螰駹礒鎪瀙酀瀵騱酅贕鱋鱭';
                 */
                //
                // Got a lot of data? Handle common seen characters only.
                //
                $big5_exception = '么功吒吭歿俞枯苒娉珮豹淚許廄琵跚愧鈾蓋穀閱璞餐縷擺黠孀踊髏涂罡傜縷槙擺踊髏礒';

                $big5_array_orig = array();
                $big5_array_new = array();
                $i = 0;
                for ($i = 0; $i < mb_strlen($big5_exception, 'UTF-8'); $i++)
                {
                    $this_big5_char = mb_substr($big5_exception, $i, 1, 'UTF-8');
                    $big5_array_new[$i] = $this_big5_char;

                    /* We are going to use preg_replace, DUAL backslash required */
                    $this_big5_char .= '\\\\';
                    $big5_array_orig[$i] = $this_big5_char;
                }

                //
                // Make all '功\' -> '功' try to remedy the big5-workaround back to normal
                //
                for ($i = 0; $i < mb_strlen($big5_exception, 'UTF-8'); $i++)
                {
                    //
                    // Use 'u' pattern modifier: http://php.net/manual/en/reference.pcre.pattern.modifiers.php
                    //
                    $new = preg_replace('/'.$big5_array_orig[$i].'/u',
                            $big5_array_new[$i],
                            $new);
                    echo $big5_array_new[$i].' ';
                }
            }

            file_put_contents($new_filename, $new);
            echo "\nDone: File Length ".strlen($str).' --> '.strlen($new)."\n";
        }
        else
        {
            echo "Already an $to_char or pure ASCII file, skip convert\n";
        }
    }
    else
    {
      echo 'Usage:
        # -------------------------------------------------------------------
        # Recursively convert all *.htm files in this forlder recursively
        # -------------------------------------------------------------------
        #
        # find . -name "*.htm" | xargs /usr/bin/ /tmp/big5_to_utf8_conv_xargs_.php
        #
        #
        # -------------------------------------------------------------------
        # Recursively "Rename" the converted UTF-8 file to overwrite original htm
        # -------------------------------------------------------------------
        #
        # find . -name "*.htm.UTF-8" | rename -f "s/\.UTF-8$//"';
        exit;
    }
}
?>


#php
#mysql
#utf8

#php by Type
#mysql by Type
#utf8 by Type
Type(Type) 2012/10/30 15:17

利用 php_big5_to_utf8_conv 轉換 MYSQL 資料庫




@ 先停止你所有的 Web Server 服務,避免還有 Transaction 發生
代碼:

$ STOP your web application (e.g. APACHE2, NGINX, IIS)



@ 利用 MYSQLDUMP 把某個 Table 先 DUMP 出來
代碼:

$ mysqldump --user=<USERNAME> -p --default-character-set=<ORIG_CHARSET> -c --insert-ignore --skip-extended-insert --skip-set-charset -r zz_mysql_table.SQL <DATABASE_NAME> <DATABASE_TABLE>


@ 透過 php_big5_to_utf8_conv 轉換 BIG-5 --> UTF-8
代碼:

$ /usr/bin/php php_big5_to_utf8_conv_xargs.php zz_mysql_table.SQL


@ 接著透過 PERL 把 TABLE struct CHARSET 改掉
@ 警告:這裡有風險,因為如果你的資料本身就有 CHARSET=xxx 這類字串;所以手動改比較好。
代碼:

$ perl -pi -w -e 's/CHARSET=<ORIG_CHAR_SET>/CHARSET=utf8/g;' zz_mysql_table.SQL.UTF-8


@ 最後把 zz_mysql_table.SQL.UTF-8 DUMP 回資料庫
代碼:

mysql --user=<USERNAME> --max_allowed_packet=32M -p --default-character-set=utf8 <DATABASE_NAME> < zz_mysql_table.SQL.UTF-8


DUMP 回去的過程仍然可能遇到錯誤



例如:
(1) 使用者當初在 BIG5 環境強行使用 UTF-8 編碼(例如很老舊的瀏覽器,不會判斷編碼),
進入資料庫的就是一團亂的資料,所以 big5 -> UTF8 自然有問題。
(2) 或者,使用者使用 big5 擴充字集,例如「愛心」符號,這個 PHP::mb_convert_encoding 可能也無法認得。

如:
代碼:

      ERROR at line 24945: Unknown command '\"'.


所以此時就是「一邊 dump 回去,一邊手動修正」,
透過 UTF-8 aware 的編輯器,看錯誤的行數,花時間手動修正。
這也是 DUMP 時加上 "--skip-extended-insert" 的理由,
SQL DUMP 檔案雖然放大,但是你可以看到 Restore 回去時的錯誤行數。

常見的「SQL 錯誤 搜尋字串」
代碼:

      ?,'  ===>  ','

      ?);  ===>  ');

      \'   ===>  \\'


手動改的原因是,如果資料庫內容內文就是「>\\\」結尾(害羞的表情符號,但是只有一隻眼睛)
或者是「這三台筆電,要選哪一個 AAA??,BBB??,CCC??」 (真的打問號,加上半型逗號)等等,
此內文就不能改,而要人工判斷。
Type(Type) 2012/10/30 15:18

附上 ICONV 和 BSD::FILE 使用教學



理論上簡單的轉換,用 iconv 也可,
但是大量轉換,或者你的資料比較複雜(混了一些中文簡體、日文、韓文),
就「不建議」使用 iconv,
而是建議「使用上述 big5_to_utf8_conv_xargs.php 」或其他包好的工具,轉換容錯都比 ICONV 好。

部分狀況 iconv 轉到一半遇到錯誤會自己爆炸,容錯能力比 PHP::MultiByte-String 差很多;
STDERR 也沒有明顯的「檔案名稱」,並不好進行例外處理。

@ ICONV BIG-5 --> UTF-8 中文轉換使用方式
代碼:

$ iconv -f BIG-5 -t -UTF-8 <ORIGINAL_BIG5_FILENAME> -o <TARGET_UTF8_FILENAME>



@ BSD::FILE 使用方式,很簡單,就是 /usr/bin/file <FILENAME>
代碼:

$ file index.html
file index.html
HTML document, UTF-8 Unicode text, with very long lines, with CRLF line terminators


$ man file

NAME
     file - determine file type

SYNOPSIS
     file [-bchiklLNnprsvz0] [--apple] [--mime-encoding] [--mime-type] [-e testname] [-F separator] [-f namefile]
          [-m magicfiles] file ...
     file -C [-m magicfiles]
     file [--help]

Type(Type) 2012/10/30 16:20

處理簡體中文、日文、韓文等 "&#數字分號" Unicode 參照碼



如果你的系統在 LATIN1/BIG-5 環境就可以處理「簡體中文、日文、韓文」
你很可能是透過 html entities 或所謂的「UNICODE 參照編碼」
等類似技術達成。

舉例:這段簡體中文、日文、繁體中文混合
代碼:

简体中文
郑竹吟
博多ラーメン
小哈工作坊鄭竹吟



實際上,資料庫是用這種方式儲存的 :: 能用 BIG5 就用 BIG5,
BIG5 沒定義的就用 Uincode Offset --> 轉成 "&# 十進位 ;" HTML Entities
代碼:

&#31616;体中文
&#37073;竹吟
博多&#12521;&#12540;&#12513;&#12531;
小哈工作坊鄭竹吟



當你的環境 BIG-5 --> UTF-8 轉好之後,
你可也想轉這種由 HTML-ENTITIES 所組成的歷史遺跡。

使用下面這個 PHP Function
代碼:

function numeric_utf8($number_char_str)
{
    return preg_replace_callback("/(&#[0-9]+;)/",
            function($m) { return mb_convert_encoding($m[1], "UTF-8", "HTML-ENTITIES"); },
            $number_char_str);
}

Type(Type) 2012/11/2 19:34

延伸閱讀:什麼是 (釵h) (奶O) (傍@) (誘l) (紫])



http://vovo2000.com/phpbb2/viewtopic-356251.html

(22,366 views)
[更多討論] 討論區 Windows, Linux, Perl, PHP, C/C++, Driver, Web 理論、應用、硬體、軟體

"BIG5 中文轉 UTF-8 中文資料庫轉換、檔案轉換工具" 傳統頁面(電腦版)

首頁 繪圖設計 工作閒聊 比賽活動 美術討論 標籤 圖片
傳統桌面版 [ 登入/註冊 ]
© Vovo2000.com Mobile Version 小哈手機版 2024