Python中如何处理汉字字符编码问题?
有个文件,包含'⻝' 11997 和食是相同的字,但是是不同的编码,
⻝ (U+2EDD)和 食 (U+98DF)的关系是:它们是同一个字的不同视觉表现形式,但 Unicode 指定 U+98DF 为标准形式,U+2EDD 为其异体形式(特别是作为部首时)。
问了一下 AI ,都是让枚举做一个 map ,有没有统一的转化这样汉字的方案,unicodedata.normalize 不行。
Python中如何处理汉字字符编码问题?
<br>import unicodedata<br>import sys<br><br>s = '⻝'<br>print(f"Python 版本: {sys.version}")<br>print(f"Unicode 版本: {unicodedata.unidata_version}")<br>print(f"字符: '{s}'")<br>print(f"Unicode: U+{ord(s):04X}")<br>print(f"字符名称: {<a target="_blank" href="http://unicodedata.name" rel="nofollow noopener">unicodedata.name</a>(s, '未知')}")<br><br># 尝试不同的归一化形式<br>forms = ['NFC', 'NFD', 'NFKC', 'NFKD']<br>for form in forms:<br> result = unicodedata.normalize(form, s)<br> print(f"{form}: '{result}' (U+{ord(result):04X}) - 是否变化: {s != result}")<br>
unicode 姿势 +1
目前知道的:
1. 字素组合字
2. 空白字符识别
这个估计是没办法 只能查
https://util.unicode.org/UnicodeJsps/confusables.jsp
规范化分解应该是针对西文的,中文不行。
Unicode CJK 区的重复字符倒挺多的
OCR 之后再跟原文比对?
http://www.unicode.org/Public/security/revision-03/confusablesSummary.txt 感谢,用这个创建一个 map 就可以了。
还挺神奇的,U+2EDD (⻝)和 U+2F29 (⼩)都是康熙部首字符:
2F29;KANGXI RADICAL SMALL;So;0;ON;<compat> 5C0F;;;;N;;;;;
2FB7;KANGXI RADICAL EAT;So;0;ON;<compat> 98DF;;;;N;;;;;
UnicodeData.txt 里面也都相应标出了 <compat> 的分解形式:一个是 U+5C0F (汉字的“小”),一个是 U+98DF (汉字的“食”),但是它们 NFKC normalize 的结果却不同:
>>> f’U+{ord(unicodedata.normalize(‘NFKC’, chr(0x2F29))):04X}’
‘U+5C0F’ (中文“小”)
>>> f’U+{ord(unicodedata.normalize(‘NFKC’, chr(0x2FB7))):04X}’
‘U+2FB7’ (仍然是康熙部首“⻝”)
感觉会不会是 Unicode 的问题……但无论如何,要想手动 normalize 的话应该把 UnicodeData.txt 里面的第六列提出来也可以。但例如 Firefox 用的似乎是 confusables.txt [1],比 UnicodeData 来说提供了更多基于字形的 normalization ,也可以考虑一下。
[1] https://github.com/unicode-org/icu/blob/main/icu4c/source/data/unidata/confusables.txt
一个中文、一个日文
等下弄错了,楼主的是 CJK RADICAL EAT ONE ,这个的确没有 compat normalization ,必须要 confusables 了……
试了下 edge 的 ctrl+f 搜索 已经做过这个转换了 搜索‘食’可以搜索到其它两个变种
#9
edge 这个是上游的 chromium 就做了吧
我们做过一个 cad shx 格式字体转为 ttf 的项目。甲方自定义的特殊字符,可以通过映射的方式转到 ttf 中,或者你直接 svg 显示
这个 case 来看 cjk 统一是对的。。
有意思的是 ‘內’ (入)却无法通过搜索找到异体字,我还特地又去查了一次百度百科,确认这个字就是内(人)的异体字
之前遇到过一样的问题,一个字是银行(2F8F),另外一个字是银行(884C),怎么匹都匹不上。
对,就是这个 https://www.unicode.org/Public/security/revision-03/confusablesSummary.txt
同一个字可能有多种形式。因为 CJk 比较特殊,可能同一个字有 3-4 种形式存在,例如:中文简体、中文繁体、日文、韩文
在Python中处理汉字字符编码,核心是理解“编码/解码”过程以及正确使用字符串类型。主要遵循以下原则:
-
明确字符串类型:在Python 3中,
str类型表示Unicode文本(如"你好"),bytes类型表示二进制数据(如b'\xe4\xbd\xa0\xe5\xa5\xbd')。这是所有处理的基础。 -
核心操作:解码与编码
- 解码(Decode):将字节序列(
bytes) 按照指定编码(如'utf-8','gbk')转换为字符串(str)。byte_data = b'\xe4\xbd\xa0\xe5\xa5\xbd' str_data = byte_data.decode('utf-8') # 输出:'你好' - 编码(Encode):将字符串(
str) 按照指定编码转换为字节序列(bytes)。str_data = '你好' byte_data = str_data.encode('utf-8') # 输出:b'\xe4\xbd\xa0\xe5\xa5\xbd'
- 解码(Decode):将字节序列(
-
关键实践场景与代码示例
- 场景一:读取文件时指定编码
使用
open()函数时,务必使用encoding参数指定与文件匹配的编码。# 读取一个UTF-8编码的文本文件 with open('file.txt', 'r', encoding='utf-8') as f: content = f.read() # content是str类型 # 读取一个GBK编码的文本文件 with open('file_gbk.txt', 'r', encoding='gbk') as f: content = f.read() - 场景二:写入文件时指定编码
写入时同样需要指定编码,以确保文件被正确保存。
text = '这是需要保存的汉字内容' with open('output.txt', 'w', encoding='utf-8') as f: f.write(text) - 场景三:处理网络数据或未知来源的字节数据
对于接收到的
bytes数据,必须先尝试解码。如果遇到UnicodeDecodeError,可能是编码猜测错误。received_bytes = b'\xc4\xe3\xba\xc3' # 可能是GBK编码的“你好” try: text = received_bytes.decode('gbk') print(text) # 输出:你好 except UnicodeDecodeError: # 尝试其他可能的编码,如‘utf-8’, ‘gb2312’等 pass - 场景四:在源代码中使用中文字符串
在Python源代码文件中,如果包含中文字符串,需要在文件顶部声明编码。通常保存文件为UTF-8编码,并声明:
# -*- coding: utf-8 -*- # 或者 # coding: utf-8 my_str = '直接使用汉字'
- 场景一:读取文件时指定编码
使用
-
通用建议与错误排查
- 统一使用UTF-8:在项目内部、数据交换和文件存储中,优先使用UTF-8编码。它是国际标准,能覆盖所有汉字字符。
- 常见错误:
UnicodeDecodeError:尝试用错误的编码解码字节数据。解决方法是确认数据源的真实编码。UnicodeEncodeError:尝试将包含特殊字符的str编码为不支持该字符的编码(如'ascii')。解决方法是使用更全面的编码(如'utf-8')或处理/忽略错误字符。
- 调试技巧:遇到乱码时,首先检查数据当前是
str还是bytes类型(print(type(data))),然后确认每一步转换(读文件、网络请求、数据库查询)是否使用了正确的编码参数。
总结:牢记“str在内,bytes在外”,所有I/O操作都明确指定编码(首选UTF-8),即可解决绝大多数汉字编码问题。



