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

相关文章
|
C++ Python Perl
终于解决VScode中python/C++打印中文全是乱码的问题了
终于解决VScode中python/C++打印中文全是乱码的问题了
终于解决VScode中python/C++打印中文全是乱码的问题了
|
数据采集 算法 Linux
Python 抓取网页乱码原因分析
比如,在 windows 的控制台(gbk)里抓取了一个 utf-8 编码的网站。或者,在 Mac / Linux 的终端(utf-8)里抓取了一个 gbk 编码的网站。因为多数网站采用 utf-8 编码,而不少人又是用 windows,所有这种情况相当常见。
|
算法 Python
程序解码错误-由python的requests.post 请求结果乱码引起的思考
最近,在使用python的requests.post的时候,不论结果如何处理,得到的都是乱码。乱码的原因是什么?Accept-Encoding和Content-Encoding的本质是什么?
474 0
python乱码,python编码,python中文编码转换
python乱码,python编码,python中文编码转换
|
JavaScript Python
一日一技:Python写的csv文件,如何让 Excel 双击打开不乱码?
一日一技:Python写的csv文件,如何让 Excel 双击打开不乱码?
253 0
|
Python
Python编程:sublime打开中文文本乱码
Python编程:sublime打开中文文本乱码
132 0
Python编程:sublime打开中文文本乱码
|
数据采集 JSON 中间件
Python爬虫:python2使用scrapy输出unicode乱码
Python爬虫:python2使用scrapy输出unicode乱码
202 0
|
Python
Python mapfinance库②中文标题乱码 与 显示负数 解决方案
Python mapfinance库②中文标题乱码 与 显示负数 解决方案
612 0
Python mapfinance库②中文标题乱码 与 显示负数 解决方案
|
编解码 开发工具 Python
Python乱码九问
Python乱码九问
222 0