我有一个字符串'aúlt,我想根据字符位置获得操作的长度,依此类推。问题是第一个ë被计算两次,或者我猜ë在位置0并且'在位置1。
在Python中是否有任何可能的方法让像ë表示为1?
我正在使用UTF-8编码来输出它的实际代码和网页。
编辑:只是为什么我需要这样做的一些背景知识。我正在研究一个将英语翻译成Seneca(一种美洲原住民语言)的项目,并且显示了很多。某些单词的某些重写规则需要知道字母位置(本身和周围的字母)和其他特征,例如重音和其他变音符号。
答案 0 :(得分: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
当然,您也可以访问unicode
对象中的单个字符,就像访问str
对象一样(它们都是从basestring
继承的,因此具有相同的方法) :
>>> test = u'ë́aúlt'
>>> print test[0]
ë
如果您开发本地化应用程序,通常最好只在内部使用unicode
- 对象,通过解码您获得的所有输入。完成工作后,您可以将结果再次编码为“UTF-8”。如果你坚持这个原则,你将永远不会看到你的服务器崩溃,因为你可能会得到任何内部UnicodeDecodeError
;)
PS:请注意,在Python 3中,str
和unicode
数据类型发生了显着变化。在Python 3中,只有unicode字符串和普通字节字符串不能再混合使用。这应该有助于避免使用unicode处理常见的陷阱...
此致 克里斯托弗
答案 1 :(得分:5)
问题是第一个ë被计算两次,或者我猜ë在位置0并且'在位置1。
是。这就是Unicode定义代码点的方式。通常,您可以要求Python使用Unicode规范化转换字母和单独的“组合”变音标记,如U + 0301 COMBINING ACUTE ACCENT:
>>> unicodedata.normalize('NFC', u'a\u0301')
u'\xe1' # single character: á
然而,在“带有分音符和重音符号的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
答案 2 :(得分:1)
您可以做的最好的事情是使用unicodedata.normalize()
来分解角色,然后过滤掉重音。
不要忘记在代码中使用unicode
和unicode文字。
答案 3 :(得分:0)
您使用的是哪个Python版本? Python 3.1没有这个问题。
>>> print(len("ë́aúlt"))
6
此致 Djoudi
答案 4 :(得分:0)
你说:我有一个字符串'aúlt,我想根据字符位置获得操作的长度,等等。问题是第一个ë被计算两次,或者我猜ë在位置0并且'在位置1。
处理任何Unicode问题的第一步是确切知道数据中的内容;别猜。在这种情况下,你的猜测是正确的;它并不总是如此。
“究竟是什么在你的数据中”:使用repr()内置函数(除了unicode之外还有很多东西)。在你的问题中显示repr()输出的一个有用的优点是,回答者的确拥有你所拥有的。请注意,您的文本仅显示四个位置,而不是一些浏览器/字体显示5个 - “e”及其变音符号和“a”在一个位置被拼凑在一起。
您可以使用unicodedata.name()函数告诉您每个组件是什么。
以下是一个例子:
# coding: utf8
import unicodedata
x = u"ë́aúlt"
print(repr(x))
for c in x:
try:
name = unicodedata.name(c)
except:
name = "<no name>"
print "U+%04X" % ord(c), repr(c), name
结果:
u'\xeb\u0301a\xfalt'
U+00EB u'\xeb' LATIN SMALL LETTER E WITH DIAERESIS
U+0301 u'\u0301' COMBINING ACUTE ACCENT
U+0061 u'a' LATIN SMALL LETTER A
U+00FA u'\xfa' LATIN SMALL LETTER U WITH ACUTE
U+006C u'l' LATIN SMALL LETTER L
U+0074 u't' LATIN SMALL LETTER T
现在阅读@ bobince的回答: - )