环境

  • Windows 10 x64

  • Python 3.6.3

关于 gb18030 编码

  •  GB 18030 wiki:

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

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

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

解码错误的处理方式

  • 错误:

UnicodeDecodeError: 'gb18030' codec can't decode byte 0xff in position 129535: illegal multibyte sequence
  • 异常对象:

  • 方案一:自定义 replace_errors:

import codecs# gb18030 乱码 handlerdef 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)	# 注册自定义handlercodecs.register_error("myreplace", WalkerGB18030ReplaceHandler)

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

# 修理 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、

2、

*** ***