Python 反转 UTF-8 字符串

Python reversing an UTF-8 string

我目前正在学习 Python 作为斯洛文尼亚人,我经常使用 UTF-8 字符来测试我的程序。通常一切正常,但有一个问题我无法超越。即使我在文件顶部声明了编码,当我尝试反转包含特殊字符的字符串时它也会失败

#-*- coding: utf-8 -*-

a = "čšž"
print a    #prints čšž
b = a[::-1]
print b    #prints �šō� instead of žšč

有什么办法可以解决这个问题吗?

Python2个字符串是字节字符串,UTF-8编码的文本每个字符使用多个字节。仅仅因为您的终端设法将 UTF-8 字节解释为字符,并不意味着 Python 知道哪些字节构成一个 UTF-8 字符。

你的字节串由6个字节组成,每两个字节组成一个字符:

>>> a = "čšž"
>>> a
'\xc4\x8d\xc5\xa1\xc5\xbe'

但是,UTF-8 使用多少字节取决于字符在 Unicode 标准中的定义位置; ASCII字符(Unicode标准中的前128个字符)每个只需要1个字节,很多emoji需要4个字节!

在 UTF-8 中,顺序是 一切;反转上述字节串会反转字节,就 UTF-8 标准而言会产生一些乱码,但中间 4 个字节只是 happen 成为有效的 UTF-8 序列(对于 šō):

>>> a[::-1]
'\xbe\xc5\xa1\xc5\x8d\xc4'
-----~~~~~~~~^^^^^^^^####
  |     š       ō      |
  \                    \
   invalid UTF8 byte    opening UTF-8 byte missing a second byte

您必须将字节字符串解码为 unicode 对象,该对象由单个字符组成。反转该对象可为您提供正确的结果:

b = a.decode('utf8')[::-1]
print b

您始终可以将对象再次编码回UTF-8:

b = a.decode('utf8')[::-1].encode('utf8')

请注意,在 Unicode 中,当使用 combining characters 时,您仍然可以 运行 在反转文本时遇到问题。反转带有组合字符的文本会将组合字符放在它们组合的字符前面而不是后面,因此它们将与错误的字符组合:

>>> print u'e\u0301a'
éa
>>> print u'e\u0301a'[::-1]
áe

您可以通过将 Unicode 数据转换为其规范化形式(用 1-codepoint 形式替换组合)来避免这种情况,但是还有许多其他奇特的 Unicode 字符不能很好地处理字符串反转。