Python使用特殊字符时返回字符串长度错误
我有一个字符串 ë́aúlt,我想要计算它的长度,并根据字符的位置进行一些操作。问题是,第一个 ë́ 被计算了两次,或者说 ë 在位置 0,而 ´ 在位置 1。
有没有办法在 Python 中把像 ë́ 这样的字符算作一个字符呢?
我在实际的代码和输出到网页上时使用的是 UTF-8 编码。
补充一下背景,为什么我需要这样做。我正在做一个项目,把英语翻译成塞内卡语(这是一种美洲土著语言),而 ë́ 这个字符出现得比较多。某些单词的重写规则需要知道字母的位置(包括它自己和周围的字母)以及其他特征,比如重音符号和其他变音符号。
5 个回答
你可以做的最好的事情就是使用 unicodedata.normalize()
这个方法来分解字符,然后把重音符号过滤掉。
别忘了在你的代码中使用 unicode
和 unicode 字面量。
问题在于,第一个 ë́ 被计算了两次,或者说 ë 在位置 0,而 ´ 在位置 1。
没错。这就是 Unicode 如何定义字符的。一般来说,你可以让 Python 把一个字母和一个单独的“组合”音标,比如 U+0301 组合重音符号,进行转换,这个过程叫做 Unicode 规范化:
>>> unicodedata.normalize('NFC', u'a\u0301')
u'\xe1' # single character: á
不过,Unicode 中并没有一个单独的字符表示“带有变音符和重音符的 e”,因为世界上没有任何语言使用过这个字母 ‘ë́’。(拼音中有“带有变音符和重音符的 u”,但没有 ‘e’。)因此,字体支持很差;在很多情况下,它的显示效果很糟糕,在我的网页浏览器中看起来像一团乱麻。
要找出 Unicode 字符串中“可编辑点”的位置是一项复杂的工作,需要对语言有一定的了解。这是“复杂文本布局”问题的一部分,这个领域还包括双向文本和上下文字形形状及连字等问题。要处理复杂文本布局,你需要使用一些库,比如 Windows 上的 Uniscribe,或者一般情况下的 Pango(它有 Python 接口)。
另一方面,如果你只是想在计数时完全忽略所有组合字符,你可以很容易地把它们去掉:
def withoutcombining(s):
return ''.join(c for c in s if unicodedata.combining(c)==0)
>>> withoutcombining(u'ë́aúlt')
'\xeba\xfalt' # ëaúlt
>>> len(_)
5
UTF-8是一种编码方式,用来表示各种字符,包括一些特殊字符。它会使用多个字节来表示这些特殊字符。如果你不想计算编码后字符串的长度,只需将其解码,然后在unicode
对象上使用len()
函数(注意,不要在str
对象上使用!)。
下面是一些例子:
>>> # creates a str literal (with utf-8 encoding, if this was
>>> # specified on the beginning of the file):
>>> len('ë́aúlt')
9
>>> # creates a unicode literal (you should generally use this
>>> # version if you are dealing with special characters):
>>> len(u'ë́aúlt')
6
>>> # the same str literal (written in an encoded notation):
>>> len('\xc3\xab\xcc\x81a\xc3\xbalt')
9
>>> # you can convert any str to an unicode object by decoding() it:
>>> len('\xc3\xab\xcc\x81a\xc3\xbalt'.decode('utf-8'))
6
当然,你也可以像在str
对象中那样,访问unicode
对象中的单个字符(它们都继承自basestring
,所以有相同的方法):
>>> test = u'ë́aúlt'
>>> print test[0]
ë
如果你在开发本地化应用程序,通常建议在内部只使用unicode
对象,处理所有输入时都要进行解码。完成工作后,再将结果编码为'UTF-8'。遵循这个原则,你就不会因为内部出现UnicodeDecodeError
而导致服务器崩溃;)
另外,请注意,在Python 3中,str
和unicode
的数据类型发生了很大变化。在Python 3中,只有unicode字符串和普通字节字符串,它们不能再混合使用。这应该能帮助你避免处理unicode时常见的问题……
祝好,
Christoph