【问题标题】:Unicode (Cyrillic) character indexing, re-writing in pythonUnicode(西里尔文)字符索引,用python重写
【发布时间】:2015-10-27 11:11:31
【问题描述】:

我正在处理以西里尔拼字法书写的俄语单词。除了在str 中将多少(但不是全部)西里尔字符编码为两个字符之外,一切工作正常。例如:

>>>print ["ё"]
['\xd1\x91']

如果我不想索引字符串位置或确定一个字符的位置并将其替换为另一个(比如"e",没有分音符号),这不会是一个问题。显然,2个“字符”在以u为前缀时被视为一个,如u"ё"

>>>print [u"ё"]
[u'\u0451']

但是strs 是作为变量传递的,因此不能以 u 为前缀,而unicode() 给出了UnicodeDecodeError(ascii 编解码器无法解码...)。

那么...我该如何解决这个问题?如果有帮助,我正在使用 python 2.7

【问题讨论】:

  • 然后可以用str.format作为前缀或者使用unicode的正确编码

标签: python python-2.7 unicode


【解决方案1】:

这里有两种可能的情况。

您的str 要么代表有效的 UTF-8 编码数据,要么不代表。

如果它代表有效的 UTF-8 数据,您可以使用 mystring.decode('utf-8') 将其转换为 Unicode 对象。在它是 unicode 实例之后,它将按字符而不是按字节进行索引,正如您已经注意到的那样。

如果它有无效的字节序列...你有麻烦了。这是因为“这个字节代表哪个字符?”的问题。不再有明确的答案。当存在实际上根本不代表 UTF-8 中的特定 Unicode 字符的字节序列时,您将不得不确切地确定您所说的“第三个字符”的意思......

也许解决此问题的最简单方法是将ignore_errors 标志用于decode()。这将完全丢弃无效的字节序列,只为您提供字符串的“正确”部分。

【讨论】:

  • 然后如果我想把它移回原来的两字节格式,我用mystring.encode('ascii')?
  • @sautedman 这不是两字节格式 - UTF-8 是可变长度编码。但是,是的,如果您愿意,您可以调用“编码”。
【解决方案2】:

这些实际上是不同的编码:

>>>print ["ё"]
['\xd1\x91']
>>>print [u"ё"]
[u'\u0451']

您看到的是列表中元素的__repr__。不是 unicode 对象的 __str__ 版本。

但是 strs 是作为变量传递的,所以不能 以 u 为前缀

你的意思是数据是字符串,需要转成unicode类型:

>>> for c in ["ё"]: print repr(c)
...
'\xd1\x91'

您需要将两字节字符串强制转换为双字节宽度的 unicode:

>>> for c in ["ё"]: print repr(unicode(c, 'utf-8'))
...
u'\u0451'

你会看到这个转换非常好。

【讨论】:

    【解决方案3】:

    要将字节转换为Unicode,需要知道对应的字符编码并调用bytes.decode

    >>> b'\xd1\x91'.decode('utf-8')
    u'\u0451'
    

    编码取决于数据源。它可以是任何东西,例如,如果数据来自网页;见A good way to get the charset/encoding of an HTTP response in Python

    不要在字节文字中使用非 ascii 字符(在 Python 3 中明确禁止使用)。添加 from __future__ import unicode_literals 以将所有 "abc" 文字视为 Unicode 文字。

    注意:单个用户感知的字符可能跨越多个 Unicode 代码点,例如:

    >>> print(u'\u0435\u0308')
    ё
    

    【讨论】:

    • 我假设在你的最后一个例子中,你提供了一个带有组合变音符号的“e”?
    • 是的,它正在结合分音符。 unicodedata.normalize('NFC', u'\u0435\u0308') == u'\u0451' == u'ё'
    猜你喜欢
    • 2013-04-19
    • 1970-01-01
    • 1970-01-01
    • 2020-08-14
    • 1970-01-01
    • 2011-12-06
    • 2017-04-19
    • 1970-01-01
    • 2016-06-15
    相关资源
    最近更新 更多