Python:在包含代理项对时获取正确的字符串长度

时间:2012-10-16 03:14:23

标签: python surrogate-pairs

考虑以下IPython上的交流:

In [1]: s = u'華袞與緼同歸'

In [2]: len(s)
Out[2]: 8

正确的输出应该是7,但由于这七个中文字符中的第五个具有高Unicode代码点,因此它以UTF-8表示为“代理对”,而不仅仅是一个简单的代码点,因此Python认为它是两个字符而不是一个。

即使我使用unicodedata,它将代理项对正确地作为单个代码点(\U00026177)返回,但在传递给len()时仍会返回错误的长度:

In [3]: import unicodedata

In [4]: unicodedata.normalize('NFC', s)
Out[4]: u'\u83ef\u889e\u8207\u7dfc\U00026177\u540c\u6b78'


In [5]: len(unicodedata.normalize('NFC', s))
Out[5]: 8

如果不采取像UTF-32重新编译Python这样的重大步骤,有没有一种简单的方法可以在这样的情况下获得正确的长度?

我正在使用IPython 0.13,Python 2.7.2,Mac OS 10.8.2。

3 个答案:

答案 0 :(得分:7)

我认为这已经在3.3中得到了解决。参见:

http://docs.python.org/py3k/whatsnew/3.3.html
http://www.python.org/dev/peps/pep-0393/(搜索wstr_length

答案 1 :(得分:6)

我在Python 2上创建了一个函数:

SURROGATE_PAIR = re.compile(u'[\ud800-\udbff][\udc00-\udfff]', re.UNICODE)
def unicodeLen(s):
  return len(SURROGATE_PAIR.sub('.', s))

通过用单个字符替换代理对,我们'修复'len函数。在普通字符串上,这应该非常有效:由于模式不匹配,原始字符串将被返回而不进行修改。它也适用于宽(32位)Python构建,因为不会使用代理对编码。

答案 2 :(得分:3)

您可以在Python中覆盖len函数(请参阅:How does len work?)并在其中添加if语句以检查超长的unicode。