Python中unicode字符串长度的混淆

14

已经有不少帮助了,但我仍然感到困惑。

我有一个像这样的 Unicode 字符串:

title = u'test'
title_length = len(title) #5

但是!我需要标题长度为6。客户希望它是6,因为他们似乎在后端计算方式不同。

为了解决这个问题,我编写了这个小助手,但我确定它可以改进(拥有足够的编码知识),或者甚至是错误的。

title_length = len(title) + repr(title).count('\\U') #6

1. 有没有更好的方法让长度变为6?:-)

我假设 Python 正在计算 Unicode 字符的数量,这个数量是5。而客户端正在计算字节数?

2. 如果有需要4个字节的其他 Unicode 字符,我的逻辑会出问题吗?

运行 Python 2.7 ucs4。


3
客户端计算 UTF-16 代理对。 - Martijn Pieters
2
当我尝试运行这两行代码时,它显示长度为6。 - ssundarraj
1
@ssundarraj:看看我的答案;你正在运行Python 2 UCS2版本。使用Python 3.3或更高版本,或获取UCS4版本。 - Martijn Pieters
1个回答

15

你有5个代码点。其中一个代码点位于基本多语言面外,这意味着这些代码点的UTF-16编码必须使用两个代码单元表示字符

换句话说,客户端依赖于实现细节,并且正在做错误的事情。他们应该计算代码,而不是代码单元。有几个平台经常发生这种情况;Python 2 UCS2版本就是其中之一,但Java开发人员经常忘记区别,Windows API也是如此。

您可以将文本编码为UTF-16,然后将字节数除以2(每个UTF-16代码单元为2个字节)。选择utf-16-leutf-16-be变体,以不包括BOM标记在长度内:

title = u'test'
len_in_codeunits = len(title.encode('utf-16-le')) // 2

如果您正在使用Python 2(而且根据字符串前缀u,您很可能在使用Python 2),请注意,有两种不同的Python版本,这取决于您如何构建它。根据构建时配置开关,您将拥有UCS-2或UCS-4版本;前者也在内部使用代理项,并且在那里您的title值长度也为6。请参见Python返回单个Unicode字符字符串长度为2


客户端确实是使用Java编写的,你怎么知道他们正在计数UTF-16代理对呢?难道不可能是UTF-8或UTF-32吗?我能确定他们总是计算两个代码单元吗?根据代码点,它可能会更多。你计数的方法看起来确实更优雅。 :-) 非常感谢您提供这个很棒的解释! - kev
如果在不同的UTF编解码器中计算代码单元,计数将会大相径庭(UTF-8为8,UTF-32为5)。是的,UTF-16始终使用一个或两个代码单元,请参见我的答案中的维基百科链接。Java代码可以修复;请参阅[JSR-204](https://jcp.org/en/jsr/detail?id=204)和[codePointCount()方法](http://docs.oracle.com/javase/7/docs/api/java/lang/String.html#codePointCount(int,%20int))。 - Martijn Pieters

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接