【问题标题】:Python Unicode BugPython Unicode 错误
【发布时间】:2014-04-24 22:30:38
【问题描述】:

我正在使用 PyPy 在 RPython 中制作一个虚拟机。问题是,当我尝试添加 unicode 支持时,我发现了一个不寻常的问题。我将在示例中使用字母“á”。

# The char in the example is á
print len(char)

OUTPUT:
2

我了解字母“á”如何占用两个字节,因此长度为 2。但问题是当我使用下面的这个示例时,我遇到了问题。

# In this example instr = "á" (including the quotes)
for char in instr:
    print hex(int(ord(char)))

OUTPUT:
0x22
0xc3
0xa1
0x22

你可以有 4 个数字。 0x22 用于引号,但引号之间只有 1 个字母,但有两个数字。我的问题是,我测试这个脚本的一些机器产生了这个输出:

OUTPUT:
0x22
0xe1
0x22

有没有办法让两台机器上的输出相同?每个脚本都完全相同。

【问题讨论】:

  • 不相关:将字节字符串转换为十六进制字符串:print(binascii.hexlify(instr))
  • 您问题中的代码是针对 Python 2 的(根据print 语句和'"á"' 的内容判断)

标签: python python-3.x unicode utf-8


【解决方案1】:

程序在两台机器上的输入不同:

In [154]: '\xe1'.decode('cp1252').encode('utf_8') == '\xc3\xa1'
Out[154]: True

当您在控制台中键入 á 时,您可能会看到字形 á,但控制台会将其转换为字节。它转换成的特定字节取决于控制台使用的编码。在 Windows 机器上,可能是 cp1252,而在 Unix 机器上,可能是 utf-8

因此您可能看到输入相同,但控制台(以及程序)接收不同的输入。

如果您的程序要使用适当的编码对字节进行解码,然后使用 unicode,那么这两个程序将在该点之后以相同的方式运行。如果您从sys.stdin 接收字节,那么sys.stdin.encoding 将是Python 检测到控制台正在使用的编码。

【讨论】:

  • 输入会有什么变化?
【解决方案2】:

您将这个问题标记为“Python-3.x”——是否有可能某些机器正在运行 Python 2.x,而其他机器正在运行 Python 3.x?

字符á 实际上是U+00E1,所以在 Python 3.x 系统上,我希望看到您的第二个输出。由于 Python3 中的字符串默认为 Unicode,len(char) 将为 3(包括引号)。

在 Python 2.x 中,字符串中的相同字符将有两个字节长,并且(取决于您的输入法)将在 UTF-8 中表示为 \xc3\xa1。在该系统上,len(char) 将为 4,您将看到您的第一个输出。

【讨论】:

    【解决方案3】:

    问题在于您使用字节串来处理文本数据。您应该改用 Unicode。

    这意味着您需要知道输入数据的字符编码——There Ain't No Such Thing As Plain Text

    如果您知道字符编码,那么很容易将字节串转换为 Unicode,例如:

    unicode_text = bytestring.decode(encoding)
    

    它应该可以解决您最初的问题。

    还有Unicode normalization forms 比如:

    import unicodedata
    
    norm_text = unicodedata.normalize('NFC', unicode_text)
    

    如果我不更改程序中的编码,例如如何输出 unicode 字符?

    您可能意味着您有一个字节序列,例如'\xc3\xa1'(两个字节),可以使用某些字符编码解释为文本,例如,它是 utf-8 中的U+00E1 Unicode codepoint。在不同的字符编码中可能会有所不同。请阅读我在上面提供的链接The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)

    除非您的终端意外使用与输入文件中的数据相同的字符编码;您需要能够从一种字符编码转换为另一种。否则输出将被损坏,例如,您可能会在屏幕上看到 ├б 而不是 á

    在普通 Python 中,您可以使用 bytes.decode、unicode.encode 方法(或直接使用 codecs 模块)。我不知道在RPython中是否可以。

    【讨论】:

    • 有没有什么方法可以在没有解码方法的情况下解码字符串?在 RPython 中我不能使用 .decode 方法。
    • @user3566150:我不知道 RPython 是否支持编码。数据从何而来?为什么它在不同的机器上使用不同的字符编码?
    • 数据来自文本文件。 RPython 默认使用 ascii,因为它基于 Python 2。你可以使用 unicode() 函数,只要它只有 1 个参数并且你可以说 u"Some string" 来生成 unicode 字符串,但你可以使用 "Something"。解码(“utf8”)。 RPython 中有几个函数可以处理 unicode,但我也发现了其中的一个问题。例如,他们可以转换转义的 unicode \uE1,但他们不能处理每个 unicode 字符,当我尝试解码过去 \uF5 时,它会显示 Unicode Decode Error。
    • @user3566150:不要混合使用 RPython 源代码 (ascii) 的字符编码和可能任何的外部数据编码/i>。 á 不是 ascii。谁写文件?为什么数据文件中的字符编码不一样?
    • 如果我不更改程序中的编码,例如如何输出 unicode 字符?
    猜你喜欢
    • 2023-04-07
    • 1970-01-01
    • 1970-01-01
    • 2011-08-05
    • 2021-09-01
    • 2011-03-14
    • 2016-04-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多