【环境】
-
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
|
-
异常对象:UnicodeDecodeError
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)
|
【相关阅读】
*** walker 的流水账 ***
本文转自walker snapshot博客51CTO博客,原文链接http://blog.51cto.com/walkerqt/2054425如需转载请自行联系原作者
RQSLT