为了账号安全,请及时绑定邮箱和手机立即绑定

Python3 处理 gb18030 乱码

标签:
Python

环境

  • Windows 10 x64

  • Python 3.6.3


关于 gb18030 编码

  •  GB 18030 wiki:https://zh.wikipedia.org/wiki/GB_18030

  • 单字节,其值从0到0x7F。

  • 双字节,第一个字节的值从0x81到0xFE,第二个字节的值从0x40到0xFE(不包括0x7F)。

  • 四字节,第一个字节的值从0x81到0xFE,第二个字节的值从0x30到0x39,第三个字节从0x81到0xFE,第四个字节从0x30到0x39。


解码错误的处理方式

  • 错误:

1UnicodeDecodeError: 'gb18030' codec can't decode byte 0xff in position 129535: illegal multibyte sequence
  • bytes.decode

  • codecs.register_error 样例

  • 异常对象:UnicodeDecodeError

  • 方案一:自定义 replace_errors:

import codecs


# gb18030 乱码 handler

def WalkerGB18030ReplaceHandler(exc):

print('exc.start: %d' % exc.start)

print('exc.end: %d' % exc.end)

print('exc.encoding: %s' % exc.encoding)

print('exc.reason: %s' % exc.reason)

text = ''

for ch in exc.object[exc.start:exc.end]:

print('ch:')

print(ch)

text += ('0x%02X' % ch)

return (text, exc.end)



* 方案二:自定义编码清洗

# 修理 gb18030文件

# 将乱码转化为十六进制字符串,例如:b'\xff' 转为字符串 0xFF

# 将不可打印单字节转为十六进制字符串,例如:b'\xff' 转为字符串 0x7F

# srcFile 为原始 gb18030文件

# dstFile 为修理后的 gb18030文件

# explicit 控制是否转换为不可打印字符: explicit 为 False 是不转换(默认),否则转换

def RepairGB18030File(srcFile, dstFile, explicit=False):

    with open(srcFile, mode='rb') as fin:

        byteText = fin.read()

    byteLength = len(byteText)   

    print('byteLength: %d' % byteLength)

     

    pos = 0       # 位置

    byteList = list()

    # 末尾添加2对\r\n防止pos溢出

    byteText += b'\x0d\x0a\x0d\x0a'

    while pos < byteLength:  

        byte1 = bytes([byteText[pos]])

        byte2 = bytes([byteText[pos+1]])

        byte3 = bytes([byteText[pos+2]])

        byte4 = bytes([byteText[pos+3]])

         

        # 单字节汉字(正常)

        if b'\x00' <= byte1 <= b'\x7f':     

            pos += 1

            if byte1.decode('gb18030').isprintable(): # 可打印字符

                byteList.append(byte1)

                continue

                 

            if byte1 in (b'\x0d', b'\x0a'): # 换行符

                byteList.append(byte1)

                continue

                 

            if explicit:   # 要求转换不可打印字符  

                byteNew = ("0x%02X" % ord(byte1)).encode('gb18030')

                byteList.append(byteNew)   

            else:           # 不要求转换不可打印字符

                byteList.append(byte1)         

                 

        # 多字节汉字(双字节或四字节)      

        elif b'\x81' <= byte1 <= b'\xfe':   

            #双字节(正常)

            if (b'\x40' <= byte2 <= b'\x7e') or (b'\x80' <= byte2 <= b'\xfe'):  

                pos += 2

                byteList.extend([byte1, byte2])

                continue

                 

            #四字节   

            if b'\x30' <= byte2 <= b'\x39': 

                # 四字节(正常)

                if (b'\x81' <= byte3 <= b'\xfe') or (b'\x30' <= byte4 <= b'\x39'):

                    pos += 4

                    byteList.extend([byte1, byte2, byte3, byte4])

                    continue

                 

                # 四字节乱码

                pos += 1  #错误的时候只能移动一个字节

                byteNew = ("0x%02X" % ord(byte1)).encode('gb18030')

                byteList.append(byteNew)

                continue

             

            # 双字节乱码

            #0x00-0x2f、0x7f、0xff

            pos += 1  #错误的时候只能移动一个字节

            byteNew = ("0x%02X" % ord(byte1)).encode('gb18030')

            byteList.append(byteNew)

        else:

            # 单字节乱码       

            #应该只剩 0x80 和 0xff

            byteNew = ("0x%02X" % ord(byte1)).encode('gb18030') #4个字节

            pos += 1  #错误的时候只能移动一个字节

            byteList.append(byteNew)

         

    repairedText = b''.join(byteList).decode('gb18030')

     

    with open(dstFile, mode='w', encoding='gb18030') as fout:

        fout.write(repairedText)




相关阅读

1、关于 Python3 的编码

2、汉字字符集编码查询



点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消