现在的位置: 首页 > IT运维 > 正文

python版gb转big5, 复活pygb2big.py

2021年01月24日 IT运维 ⁄ 共 2447字 暂无评论

想找gbk到big5转换的python版,网上到处是同一篇文章,讲了原理,却发生了最稀奇的事情:到处都找不到pygb2big.py文件,于是操刀根据原理复原了pygb2big.py , 打破惯例,先提供下载,再展示代码,最后才是解说:

# -*- coding: utf-8 -*-
import getopt
import sys


def usage():
    print('big5 file to gbk file:')
    print('\tpygb2big.py -b inputfile outputfile ')
    print('gbk file to big5 file:')
    print('\tpygb2big.py -g inputfile outputfile ')


def gb2big5(text):
    chrBIG = open('gbk2big.txt', 'rb').read()
    i = 0
    lentext = len(text)
    desc = bytearray(lentext)
    while i < lentext:
        ch1 = text[i]
        if i + 1 == lentext:
            desc[i] = ch1
            break
        ch2 = text[i + 1]
        if ch1 < 0:
            ch1 += 256
        if ch2 < 0:
            ch2 += 256

        if 0x81 <= ch1 <= 0xfe and (0x40 <= ch2 < 0x7f or 0x7f < ch2 <= 0xfe):  # is gb char
            index = ((ch1 - 0x81) * 190 + (ch2 - 0x40) - int(ch2 / 128)) * 2
            desc[i] = chrBIG[index]
            desc[i + 1] = chrBIG[index + 1]
            i += 2
        else:
            desc[i] = ch1
            i += 1
    result = desc.decode('big5', errors='ignore').strip()
    return result


def big2gb(text):
    chrGBK = open('big2gbk.txt', 'rb').read()
    i = 0
    lentext = len(text)

    desc = bytearray(lentext)
    while i < lentext:
        ch1 = text[i]
        if i + 1 == lentext:
            desc[i] = ch1
            break
        ch2 = text[i + 1]
        if ch1 < 0:
            ch1 += 256
        if ch2 < 0:
            ch2 += 256

        if 0xa1 <= ch1 <= 0xfe:  # is big5 char
            if ch2 < 0xa1:
                ch2 -= 0x40
            if ch2 >= 0xa1:
                ch2 = ch2 - 0xa1 + 0x7e - 0x40 + 1
            index = 2 * ((ch1 - 0xa1) * 157 + ch2)
            desc[i] = chrGBK[index]
            desc[i + 1] = chrGBK[index + 1]
            i += 2
        else:
            desc[i] = ch1
            i += 1
    result = desc.decode('gbk', errors='ignore').strip()
    return result


method = 'gbk2big'
try:
    options, args = getopt.getopt(sys.argv[1:], "ubg", ["usage", "big2gbk", "gbk2big"])
except getopt.GetoptError:
    sys.exit()
for name, value in options:
    if name in ("-u", "--usage"):
        usage()
        sys.exit()
    if name in ("-b", "--big2gbk"):
        method = 'big2gbk'

if not args or len(args) != 2:
    usage()
    sys.exit()

text = open(args[0], 'rb').read()
res = ''

if method == 'gbk2big':
    res = gb2big5(text)
elif method == 'big2gbk':
    res = big2gb(text)

f = open(args[1], 'w')
f.write(res)

GB碼与BIG5是中國人常用的兩种編碼集。GB碼為大陸使用,BIG5為香港与台灣使用。每個編碼都由2個字符构成,高字節在前,低字節在后。下面我將使用Python實現的編碼轉換的程序向大家作一個介紹。關于編碼的一些知識大家可以去网上查找,本人不再贅述。 GB碼是大陸使用的編碼集。以前使用的為GB-2312編程,它只有常用字,字數有限。后國家制定了新的GBK編碼,漢字已經達到了2万多。GBK完全兼容原GB-2312編碼,也就是說一個GB2312的編碼在GBK上是一模一樣的。這里所介紹的轉換是以GBK為基礎的,因此适用性很廣。GBK編碼中不僅包括了原GB-2312編碼,同時也包括了許多簡碼的繁体碼,同時還有許多的符號与不常用漢字。GBK編碼的范圍是:高字節從0x81到0xFE,低字節從0x40到0xFE,同時不包括0x7F。這樣如果我們將其排成一個矩形,看上去就少了xx7F一根線。

編碼的定位
那么如何定位一個GBK碼呢?當我們拿到一個編碼時,如何判斷是不是一個GBK碼,如果是GBK碼如何定位它的位置呢?

判斷一個GBK碼應該比較簡單,我們只要根据它的有效范圍進行判定即可。如:

if 0x81<=ch1<=0xFE and (0x40<=ch2<=0x7E or 0x7E<=ch2<=0xFE): #is gb char

這里ch1和ch2分別是一個字符的高字節和低字節。

如何定位(為什么要定位我們在后面講)?首先介紹一下碼表。碼表是所有編碼放
在一起形成的,你可以將其放在文件中(這里講述的是將編碼放在文件中)。我們
在存放編碼時是將有實際意義的編碼放在了一起(因為有一些組合是不存在的),
而且是按字節大小的順序放的。根据GBK的編碼范圍,我們可以設想一個二維坐標
,縱坐標是高字節,橫坐標是低字節,每一個交叉點上是一個漢字,占兩個字節。
這樣一行上的漢字個數應該為0xFE-0x40+1-1=190(加1是因為要把0x40也算進去。
減1是因為要把7F去掉)。定位時,我們先用高字節減去0x81,得到縱坐標偏移量
。用低字節減去0x40得到橫坐標偏移量。用縱坐標偏移量乘以每個漢字個數,加上
橫坐標偏移量就得到漢字的偏移量。再乘以2得到字節的偏移量。那么定位算法為:

index=((ch1-0x81)190+(ch2-0x40)-(ch2/128))2

上面的算法中有-(ch2/128)。這是因為GBK中沒有7F碼,因此當ch2小于7F時,
ch2/128=0,則表示7F沒有計算在內。而當ch2大于7F時,ch2/128=1,則表示多算
了7F一值,因此要去掉。由于一個漢字有兩個字節,故要乘以2。這樣我們就得到
一個GBK漢字在碼表中的字節位置了。

BIG5是香港和台灣地區使用的編碼集。它的范圍為:高字節從0xA0到0xFE,低字節從0x40到0x7E,和0xA1到0xFE兩部分。判斷一個漢字是否是BIG5編碼,可以如上對字符的編碼范圍判斷即可。如何定位呢?那么也想象所有編碼排列為一個二維坐標,縱坐標是高字節,橫坐標是低字節。這樣一行上的漢字個數:
(0x7E-0x40+1)+(0xFE-0xA1+1)=157。那么定位算法分兩塊,為:

if 0x40<=ch2<=0x7E: #is big5 char
index=((ch1-0xA1)157+(ch2-0x40))2
elif 0xA1<=ch2<=0xFE: #is big5 char
index=((ch1-0xA1)157+(ch2-0xA1+63))2

對于第二塊,計算偏移量時因為有兩塊數值,所以在計算后面一段值時,不要忘了
前面還有一段值。0x7E-0x40+1=63。

編碼轉換上面,我們已經可以得到GBK漢字和BIG5的字節位置。那么就可以開始進行轉換了。對于轉換我原以為有一個特別的算法,能夠按照兩种編碼的不同,簡單地通過計算就可以得出結果來,其實是不存在這种算法的。真正的做法是通過建立轉換碼表文件實現的。即對于GBK碼表,將原位置上的GBK漢字改成相應的BIG5漢字。對于BIG5碼表,將原位置上的BIG5漢字改成相應的GBK漢字。這樣,由于原來漢字的位置沒有變,但編碼已經變成了想要轉換的編碼。通過計算出原漢字的位置,將轉換碼表中對應漢字位置的字符取出來,這樣就完成了轉換(這就是為什么要進行編碼定位的原因)。的确,程序是簡單的,但真正細致的工作是在建立轉換碼表上。我們需要從GBK轉BIG5的碼表文件,和BIG5轉GBK的碼表文件。好在這一工作已經有人完成了,在网上可以找到這种信息。本人就是在网上找到了這种對應的轉換碼表,于是完成了一個用Python做的編碼轉換程序。(想要此程序的可以去作者主頁http://pyrecord.126.com上查找)

一個用于編碼轉換的Python模塊的使用介紹程序文件名為pygb2big.py。命令行:

python pygb2big.py [-u] [-b|-g] inputfile outputfile。

它主要的命令行參數為:-b,表示將GBK轉化為BIG5;-g,表示將BIG5轉成GBK;-u,顯示程序的用法。inputfile為輸入的待處理的文件;而ouputfile為結果文件。它帶有三個轉換碼表文件,其中gbk2big.txt為GBK轉big5對照表;big2gbk.txt
為BIG轉GBKcf對照表。另一個為big2gbk-f.txt,只是提供但并未使用,它是將
BIG5轉換為繁体GBK碼。

有了這個轉換模塊,我們就可以應用于任何需要進行碼制轉換的地方了。當然,這
里只是GBK到BIG5的轉換,如果有其它的轉換碼表文件,我們也可以實現其它的轉換功能。

给我留言

您必须 [ 登录 ] 才能发表留言!

×
#