2015年5月11日 星期一

【C++】讀寫中文字 - BIG5編碼

因為從來沒有處理過讀寫中文檔案,所以沒有太大的感覺
直到最近碰到有作業要讀一本中文字典的資料才發現好像有點麻煩
加上中文字典的格式是以BIG5編碼,中間還夾雜非中文字的符號(空白、斜線)
因此又更麻煩了些

在網路上找了一下和自己反覆的嘗試
總算是成功了

原理上如果該字元是以BIG5編碼的話,則該字元會以2個byte為單位儲存
(一般英文字母、或";:<>? "之類的字元是以1個byte為單位儲存)

而剛剛好程式中的 "char" = 1 byte, "short" = 2 bytes

所以BIG5的字元剛好可以用型態 short 表示

但是到底如何知道我現在要以 2 bytes 為單位讀BIG5的字元
還是以 1 byte 為單位讀普通的字元呢 ?

查了一下BIG5的編碼規則就能知道它將2 bytes的資料表示成:
高位位元組(第一個 byte),其範圍是 0x81~0xFE
低位位元組(第二個 byte),其範圍是 0x40-0x7E 和 0xA1-0xFE
此規範以外的字元就屬於一般字元

而另一個問題是如何將讀進來的 2 bytes BIG5字元塞到型態short中
我們假設現在讀進一個字是"我",其BIG5編碼是0xA7DA
所以其高位位元組是 A7 ,低位位元組是 DA
以bit方式表示的話(2 bytes=16 bits)會是 10100111  11011010
在我的做法中會將  short 初始化為高位位元組左移8 bit所得的值 (10100111 00000000)
然後將低位位元組先和0x00FF做"and" (00000000 11011010)
最後將上述得到的兩個值做"or"便得到最後我們想要的結構 (10100111 11011010)
寫成程式大概是
short BIG52Short(char c1, char c2)
{
    return (c1 << 8) | (c2 & 0x00FF);
}
而判斷是否為BIG5字元的函式大致上是
(我將檔案一行一行讀進來的字串餵給下面函式,這邊只顯示如何運作)
(之後變數 s 應該要拿來做其他事情才對 )
void parseLine(string line) {

    for (size_t i = 0; i < line.size(); i++) {

        if (line[i] >= (char)0x81 && line[i] <= (char)0xFE) {

            if (line[i + 1] >= (char)0x40 && line[i + 1] <= (char)0x7E) {

                short s = BIG52Short(line[i], line[i + 1]);

            }

            else if (line[i + 1] >= (char)0xA1 && line[i + 1] <= (char)0xFE) {

                short s = BIG52Short(line[i], line[i + 1]);

            }

        }

    }

}