python黑魔法之编码转换
我们在使用其他语言的库做编码转换时,对于无法理解的字符,通常的处理也只有两种(或三种):
- 抛异常
- 替换成替代字符
-
跳过
但是在复杂的现实世界中,由于各种不靠谱,我们处理的文本总会出现那么些不和谐因素,比如混合编码。在这种情况下,又回到了上面的处理办法。
那么问题来了,python有没有更好地办法呢?
答案是,有!
python的编码转换流程实际上是两段式转换:
source -> unicode -> dest
首先将字符串从原始编码转换成unicode。再将unicode转换成目标编码。
第一步我们一般采用decode()或者 unicode() 这两个函数完成。
第二步我们使用encode()函数完成。
在这里我们说的黑魔法就是在第一步实现。
decode和unicode函数都有一个叫做errors的可选参数。看看官方的描述:
- errors may be given to set a different error
- handling scheme. Default is 'strict' meaning that encoding errors raise
- a UnicodeDecodeError. Other possible values are 'ignore' and 'replace'
- as well as any other name registered with codecs. register_error that is
- able to handle UnicodeDecodeErrors.
这个参数通常有三种值:
- strict 默认值。如果出现编码错误,则会抛出UnicodeDecodeError。
- ignore 跳过。
- replace 用?替换。
好了,看到最后一句话了吗?好戏上演了!
模块codec有一个函数叫做register_error。他的作用让用户可以注册自定义的errors处理方法。
用来处理UnicodeDecodeError。
我们看看函数原型:
codecs.register_error(name, error_handler)
name: 错误处理的名称。用以填写在decode函数的error参数中。
error_handler: 处理函数。该函数接受一个异常参数。
返回一个tuple,该tuple有2个元素,第一个是纠错后的字符串,第二个是继续decode的起始位置
有了上面的基本概念。我们看下具体实现:
def cjk_error(e): if not isinstance(e, UnicodeDecodeError): raise TypeError("don't know how to handle %r" % exc) if exc.end + 1 > len(exc.object): raise TypeError('unknown codec ,the object too short!') ch1 = ord(exc.object[exc.start:exc.end]) newpos = exc.end + 1 ch2 = ord(exc.object[exc.start + 1:newpos]) sk = exc.object[exc.start:newpos] if 0x81<=ch1<=0xFE and (0x40<=ch2<=0x7E or 0x7E<=ch2<=0xFE): # GBK return (unicode(sk,'cp936'), newpos) if 0x81<=ch1<=0xFE and (0x40<=ch2<=0x7E or 0xA1<=ch2<=0xFE): # BIG5 return (unicode(sk,'big5'), newpos) raise TypeError('unknown codec !') codecs.register_error("cjk_replace", cjk_replace)
上面这个是我从网上copy的。开始我觉得很不错,但是后来发现是个很不经推敲的算法。
比如utf8和gbk在前两个字节就有交集的部分。当一个utf8的字符串以gbk编码decode的时候,出现错误是从第三个字节开始(前两个字节也能够在gbk编码范围中对应到一个汉字)。
如:
a = "你" # utf8编码:'\xe4\xbd\xa0' c = unicode(a[:2],'gbk') # 正常返回 c = unicode(a, 'gbk') # UnicodeDecodeError 。错误发生在第三个字节
所以针对这种情况,做了下改进:
import codec def cjk_replace(e): if not isinstance(e, UnicodeDecodeError): raise TypeError("invalid exception type %s" e) src = e.encoding if src in ('gbk','gb18030', 'big5'): beg = e.start - 2 if beg >= 0: try: return unicode(e.object[beg:e.end], 'utf8'), e.end + 1 except: pass if exc.end + 1 > len(exc.object): raise TypeError('unknown codec ,the object too short!') ch1 = ord(exc.object[exc.start:exc.end]) newpos = exc.end + 1 ch2 = ord(exc.object[exc.start + 1:newpos]) sk = exc.object[exc.start:newpos] if src != 'gbk' and 0x81<=ch1<=0xFE and (0x40<=ch2<=0x7E or 0x7E<=ch2<=0xFE): # GBK return (unicode(sk,'cp936'), newpos) if src != 'big5' and 0x81<=ch1<=0xFE and (0x40<=ch2<=0x7E or 0xA1<=ch2<=0xFE): # BIG5 return (unicode(sk,'big5'), newpos) raise TypeError('unknown codec !') codecs.register_error("cjk_replace", cjk_replace)
当然,这个逻辑其实还是不够严谨的。虽然对于这种混合编码这种畸形活处理有点较真儿。
不过既然python提供这样的能力,大家可以一起来讨论下,我们怎么可以做的更好?

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

PHP主要是过程式编程,但也支持面向对象编程(OOP);Python支持多种范式,包括OOP、函数式和过程式编程。PHP适合web开发,Python适用于多种应用,如数据分析和机器学习。

PHP适合网页开发和快速原型开发,Python适用于数据科学和机器学习。1.PHP用于动态网页开发,语法简单,适合快速开发。2.Python语法简洁,适用于多领域,库生态系统强大。

在 Sublime Text 中运行 Python 代码,需先安装 Python 插件,再创建 .py 文件并编写代码,最后按 Ctrl B 运行代码,输出会在控制台中显示。

PHP起源于1994年,由RasmusLerdorf开发,最初用于跟踪网站访问者,逐渐演变为服务器端脚本语言,广泛应用于网页开发。Python由GuidovanRossum于1980年代末开发,1991年首次发布,强调代码可读性和简洁性,适用于科学计算、数据分析等领域。

Python更适合初学者,学习曲线平缓,语法简洁;JavaScript适合前端开发,学习曲线较陡,语法灵活。1.Python语法直观,适用于数据科学和后端开发。2.JavaScript灵活,广泛用于前端和服务器端编程。

Golang在性能和可扩展性方面优于Python。1)Golang的编译型特性和高效并发模型使其在高并发场景下表现出色。2)Python作为解释型语言,执行速度较慢,但通过工具如Cython可优化性能。

在 Visual Studio Code(VSCode)中编写代码简单易行,只需安装 VSCode、创建项目、选择语言、创建文件、编写代码、保存并运行即可。VSCode 的优点包括跨平台、免费开源、强大功能、扩展丰富,以及轻量快速。

在 Notepad 中运行 Python 代码需要安装 Python 可执行文件和 NppExec 插件。安装 Python 并为其添加 PATH 后,在 NppExec 插件中配置命令为“python”、参数为“{CURRENT_DIRECTORY}{FILE_NAME}”,即可在 Notepad 中通过快捷键“F6”运行 Python 代码。
