开发者社区> 科技探索者> 正文
阿里云
为了无法计算的价值
打开APP
阿里云APP内打开

Python3 处理 gb18030 乱码

简介:
+关注继续查看

环境

  • 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。


解码错误的处理方式

  • 错误:

1
UnicodeDecodeError: 'gb18030' codec can't decode byte 0xff in position 129535: illegal multibyte sequence
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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)
     
# 注册自定义handler
codecs.register_error("myreplace", WalkerGB18030ReplaceHandler)

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# 修理 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、汉字字符集编码查询


*** walker 的流水账 *** 

本文转自walker snapshot博客51CTO博客,原文链接http://blog.51cto.com/walkerqt/2054425如需转载请自行联系原作者


RQSLT

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
Python入门之中文乱码
python入门编码: Python 文件中如果未指定编码,有中文代码时候,在执行过程会出现报错: File "test.py", line 2 SyntaxError: Non-ASCII character '\xe4' in file test.py on line 2, but no encoding declared; see http://www.python.org/peps/pep-0263.html for details    Python中默认的编码格式是 ASCII 格式,在没修改编码格式时无法正确打印汉字,所以在读取中文时会报错。
583 0
《Python编程快速上手——让繁琐工作自动化》——1.5 第一个程序
本节书摘来自异步社区《Python编程快速上手——让繁琐工作自动化》一书中的第1章,第1.5节,作者[美] Al Sweigart,王海鹏 译,更多章节内容可以访问云栖社区“异步社区”公众号查看。 1.5 第一个程序 虽然交互式环境对于一次运行一条 Python指令很好,但要编写完整的Python程序,就需要在文件编辑器中输入指令。
1973 0
5487
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
低代码开发师(初级)实战教程
立即下载
阿里巴巴DevOps 最佳实践手册
立即下载
冬季实战营第三期:MySQL数据库进阶实战
立即下载