Unicode 字符 Ú 和 É 错误地显示为 Ú 和 É

Unicode characters Ú and É are displayed incorrectly as Ú and É

我有一个包含西班牙语文本的 UTF-8 文件,一些带有重音符号的单词在软件的 某些 中显示不正确。

我相信我的文件是正确的。例如,名称 'JESÚS' 编码为 4A 45 53 C3 9A 53.

>>> b'\x4A\x45\x53\xC3\x9A\x53'.decode('utf-8')
'JESÚS'
根据 http://www.fileformat.info/info/unicode/char/00da/index.htm.

c39a\u00da 的正确 UTF-8 编码

那么,为什么有些软件渲染不正确?

这是使用 Latin-1 编码而不是 UTF-8 的结果。两字节 UTF-8 序列被错误地解码为两个字符。

>>> 'Ú'.encode('utf-8').decode('latin-1')
'Ã\x9a'
>>> 'É'.encode('utf-8').decode('latin-1')
'Ã\x89'

http://www.fileformat.info/info/unicode/char/9a/index.htm http://www.fileformat.info/info/unicode/char/89/index.htm

这两个字符都是控制字符,所以在不同的软件中可能显示也可能不显示。

此外,重复不正确的编码解码会进一步破坏文本:

>> 'Ú'.encode('utf-8').decode('latin-1').encode('utf-8').decode('latin-1')
'Ã\x83Â\x9a'

更新: 如果您看到实际的 š 和 ‰(而不是不可见的控制字符),则错误的编码是 Windows-1252。

Windows-1252 is a superset of ISO 8859-1,可打印字符为 0x80-0x9f。

在Windows-1252码位0x9a和0x89分别对应字符šhttp://www.fileformat.info/info/unicode/char/0161/index.htm http://www.fileformat.info/info/unicode/char/2030/index.htm

>>> 'Ú'.encode('utf-8').decode('Windows-1252')
'Ú'
>>> 'É'.encode('utf-8').decode('Windows-1252')
'É'

自动检测文本编码不可靠。尽管对于我们人类而言,在许多情况下,经过一些练习后很明显,无论您提出什么程序,都可能会因某些文本输入而失败。例如,讨论字符编码错误的文本,如本页 (!)

因此,许多处理文本的程序根本不进行自动检测,而是依赖于用户指定编码。

对于 Unicode,BOM (Byte Order Mark) 可以为您提供帮助。在 UTF-8 中,如果您的文本以 8 位字符开始 0xEF 0xBB 0xBF,它可以帮助某些程序确认整个文本的编码。

另一个大型 class 程序解释 HTML 文本 - 然后您可以使用元标记,如讨论选项的问题所示:

对于所有其他程序,由他们决定 - 您有任何想要制作的示例吗?

您正在使用使用不同编解码器解码数据的软件打开文件。我的猜测是他们在 Windows 1252 codepage. This is resulting in a Mojibake 中打开它,出现乱码。

UTF-8 codec 将 Unicode 代码点编码为 可变 字节数,具体取决于编码的字符。 Unicode 标准的前 127 个字符(对应于 ASCII 标准)只需要一个字节,然后是 1920 个 Latin-1 字符,它们被编码为两个字节,依此类推,一直到 4 个字节(UCS 允许最多 6 个每个代码点的字节数)。

您的文本包含 2 个 Latin-1 字符,因此每个字符需要 2 个字节:

>>> u'Ú and É'.encode('utf8')
'\xc3\x9a and \xc3\x89'

注意空格和单词 and 是如何编码为单个字节的(Python 将它们显示为它们的 ASCII 代码点,因为这比 \x.. 转义序列更具可读性)。

您的某些软件正在使用不同的编解码器解码该数据。 CP1252 编解码器会将每个字节 解码为单个字符 ,因此 C3 被解码为 Ã,而 9A 映射为 š89:

>>> u'Ú and É'.encode('utf8').decode('cp1252')
u'\xc3\u0161 and \xc3\u2030'
>>> print u'Ú and É'.encode('utf8').decode('cp1252')
Ú and É

请注意,该示例中的 ASCII 字符(空格和单词 and)不受影响,因为 UTF-8 和 CP1252 都使用这些字符的确切字节;前 127 个字节都使用 ASCII。