Python在使用特殊字符时返回错误的字符串长度

rof*_*fle 12 python character-encoding

我有一个字符串'aúlt,我想根据字符位置获得操作的长度等等.问题是第一个ë被计算两次,或者我猜ë在位置0并且'在位置1.

在Python中是否有任何可能的方法让像ë被表示为1?

我正在使用UTF-8编码来输出它的实际代码和网页.

编辑:只是为什么我需要这样做的背景.我正在研究一个将英语翻译成Seneca(一种美洲原住民语言)的项目,并且显示了很多.某些单词的某些重写规则需要知道字母位置(本身和周围的字母)和其他特征,例如重音和其他变音符号.

tux*_*21b 18

UTF-8是一种unicode编码,它对特殊字符使用多个字节.如果你不想要编码字符串的长度,可以简单地解码它并len()unicode对象上使用(而不是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
Run Code Online (Sandbox Code Playgroud)

当然,您也可以unicode像访问对象一样访问对象中的单个字符str(它们都是继承的basestring,因此具有相同的方法):

>>> test = u'ë?aúlt'
>>> print test[0]
ë
Run Code Online (Sandbox Code Playgroud)

如果您开发本地化应用程序,通常最好只unicode在内部使用-objects,通过解码您获得的所有输入.完成工作后,您可以将结果再次编码为"UTF-8".如果你坚持这个原则,你永远不会看到你的服务器崩溃,因为UnicodeDecodeError你可能会得到任何内部的东西;)

PS:请注意,Python 3 中的strunicode数据类型发生了显着变化.在Python 3中,只有unicode字符串和普通字节字符串不能再混合使用.这应该有助于避免使用unicode处理时常见的陷阱......

此致,Christoph


bob*_*nce 5

问题是第一个ë被计算两次,或者我猜ë在位置0并且'在位置1.

是.这就是Unicode定义代码点的方式.通常,您可以要求Python使用Unicode规范化转换字母和单独的"组合"变音标记,如U + 0301 COMBINING ACUTE ACCENT:

>>> unicodedata.normalize('NFC', u'a\u0301')
u'\xe1' # single character: á
Run Code Online (Sandbox Code Playgroud)

但是,在"带有分音符和重音符号的e"中,Unicode中没有单个字符,因为世界上没有任何语言使用过字母"ë".(拼音音译具有"带有分音符和锐音"的音符,但不是"e".)因此字体支持很差; 它在许多情况下呈现得非常糟糕,并且在我的网络浏览器上是一个混乱的blob.

计算出一串Unicode代码点中的"可编辑点"是一项棘手的工作,需要相当多的语言领域知识.它是"复杂文本布局"问题的一部分,该领域还包括双向文本和上下文glpyh整形和连字等问题.要进行复杂的文本布局,您需要一个库,例如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
Run Code Online (Sandbox Code Playgroud)