Python中如何处理汉字字符编码问题?

有个文件,包含'⻝' 11997 和食是相同的字,但是是不同的编码,

⻝ (U+2EDD)和 食 (U+98DF)的关系是:它们是同一个字的不同视觉表现形式,但 Unicode 指定 U+98DF 为标准形式,U+2EDD 为其异体形式(特别是作为部首时)。

问了一下 AI ,都是让枚举做一个 map ,有没有统一的转化这样汉字的方案,unicodedata.normalize 不行。


Python中如何处理汉字字符编码问题?
19 回复

<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 之后再跟原文比对?

还挺神奇的,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 就做了吧

我这边遇到过一次异体字问题,功能是客户自行上传文件,文件名含有一些固定格式的重要信息,需要使用正则匹配解析内容,结果出现了异体字定位了很久才发现差异,怀疑客户是五笔输入并且没有选对字。解决办法是加了个 replaceAll 给全部替换掉,暂时只能这么解决了。
‘内’、‘內’

我们做过一个 cad shx 格式字体转为 ttf 的项目。甲方自定义的特殊字符,可以通过映射的方式转到 ttf 中,或者你直接 svg 显示

这个 case 来看 cjk 统一是对的。。

有意思的是 ‘內’ (入)却无法通过搜索找到异体字,我还特地又去查了一次百度百科,确认这个字就是内(人)的异体字

之前遇到过一样的问题,一个字是银行(2F8F),另外一个字是银行(884C),怎么匹都匹不上。

对,就是这个 https://www.unicode.org/Public/security/revision-03/confusablesSummary.txt

同一个字可能有多种形式。因为 CJk 比较特殊,可能同一个字有 3-4 种形式存在,例如:中文简体、中文繁体、日文、韩文

在Python中处理汉字字符编码,核心是理解“编码/解码”过程以及正确使用字符串类型。主要遵循以下原则:

  1. 明确字符串类型:在Python 3中,str类型表示Unicode文本(如"你好"),bytes类型表示二进制数据(如b'\xe4\xbd\xa0\xe5\xa5\xbd')。这是所有处理的基础。

  2. 核心操作:解码与编码

    • 解码(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'
      
  3. 关键实践场景与代码示例

    • 场景一:读取文件时指定编码 使用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 = '直接使用汉字'
      
  4. 通用建议与错误排查

    • 统一使用UTF-8:在项目内部、数据交换和文件存储中,优先使用UTF-8编码。它是国际标准,能覆盖所有汉字字符。
    • 常见错误
      • UnicodeDecodeError:尝试用错误的编码解码字节数据。解决方法是确认数据源的真实编码。
      • UnicodeEncodeError:尝试将包含特殊字符的str编码为不支持该字符的编码(如'ascii')。解决方法是使用更全面的编码(如'utf-8')或处理/忽略错误字符。
    • 调试技巧:遇到乱码时,首先检查数据当前是str还是bytes类型(print(type(data))),然后确认每一步转换(读文件、网络请求、数据库查询)是否使用了正确的编码参数。

总结:牢记“str在内,bytes在外”,所有I/O操作都明确指定编码(首选UTF-8),即可解决绝大多数汉字编码问题。

回到顶部