在 Python 中将 widechars 转换为系统 ANSI 编码

Converting widechars to system ANSI encoding in Python

我目前正在尝试让我的屏幕 reader 更好地与 Becky! Internet Mail 配合使用。我面临的问题与那里的列表视图有关。此控件不是 Unicode 识别的,但项目是在屏幕上自定义绘制的,因此当有人查看它时,所有字段的内容无论编码如何看起来都不错。然而,当通过 MSAA 或 UIA 访问时,使用非 Unicode 程序的代码页集编码的基本 ANSI 字符和邮件具有正确的文本,而使用 Unicode 编码的邮件则不然。 文本示例:

Zażółć gěslą jaźń

表示为:

ZaěĽĂłĹ,ć gęślÄ… 在这种情况下,根据以下答案,CP1250 已损坏。 然而: ⚠️

表示为: ⚠️

⏰ 代表: ⟹° 和 高生旺 代表: é«ç”źć—ş

我只是假设这些字符串损坏得无法修复,但是当 windows 10 中的 unicode beta 支持启用时,它们会正确显示。

是否可以在 Python 中模拟此行为?

解决方案需要在 Python 2 和 3 中都有效。

目前我只是简单地将这些字符的已知组合替换为它们的正确表示,但这不是很好的解决方案,因为包含替换和要替换的字符的列表需要根据每个新发现的字符进行更新。

你的utf-8解码为cp1250。

我在python3中所做的是这样的:

orig = "Zażółć gęślą jaźń"
wrong = "Zażółć gęślą jaźń"

for enc in range(437, 1300):
    try:
        res = orig.encode().decode(f"cp{enc}")
        if res == wrong:
            print('FOUND', res, enc)
    except:
        pass

...结果是 1250 代码页。

所以你的解决方案应该是:

import sys

def restore(garbaged):
    # python 3
    if sys.version_info.major > 2:
        return garbaged.encode('cp1250').decode()
    # python 2
    else:
        # is it a string
        try:
            return garbaged.decode('utf-8').encode('cp1250')
        # or is it unicode
        except UnicodeEncodeError:
            return garbaged.encode('cp1250')

编辑:

"高生旺"无法从é«ç”źć—ş恢复的原因:

"高生旺".encode('utf-8')b'\xe9\xab\x98\xe7\x94\x9f\xe6\x97\xba'.

问题出在 \x98 部分。在 cp1250 中没有该值的字符集。如果你试试这个:

"高生旺".encode('utf-8').decode('cp1250')

您将收到此错误:UnicodeDecodeError: 'charmap' codec can't decode byte 0x98 in position 2: character maps to <undefined>

获得"é«ç”źć—ş"的方法是:

"高生旺".encode('utf-8').decode('cp1250', 'ignore')

但是ignore部分很关键,会导致数据丢失:

'é«ç”źć—ş'.encode('cp1250')b'\xe9\xab\xe7\x94\x9f\xe6\x97\xba'

如果你比较这两个:

b'\xe9\xab\xe7\x94\x9f\xe6\x97\xba'
b'\xe9\xab\x98\xe7\x94\x9f\xe6\x97\xba'

您会看到缺少 \x98 字符,因此当您尝试恢复原始内容时,您会得到一个 UnicodeDecodeError: 'utf-8' codec can't decode bytes in position 0-1: invalid continuation byte

如果你试试这个:

'é«ç”źć—ş'.encode('cp1250').decode('utf-8', 'backslashreplace')

结果将是 '\xe9\xab生旺'\xe9\xab\x98 可以解码为 ,从 \xe9\xab 解码是不可能的。