文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Python3 处理 gb18030 乱

2023-01-31 08:14

关注

环境

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


解码错误的处理方式

  • 错误:

UnicodeDecodeError: '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)
	
# 注册自定义handler
codecs.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、关于 Python3 的编码

2、汉字字符集编码查询


*** walker 的流水账 *** 


阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯