【问题标题】:Returning the first N characters of a unicode string返回 unicode 字符串的前 N ​​个字符
【发布时间】:2011-01-10 08:50:00
【问题描述】:

我有一个 unicode 字符串,我需要返回前 N 个字符。 我正在这样做:

result = unistring[:5]

但当然是 unicode 字符串的长度!= 字符的长度。 有任何想法吗?唯一的解决方案是使用 re?

编辑:更多信息

unistring = "Μεταλλικα" #Metallica written in Greek letters
result = unistring[:1]

返回-> ?

我认为 unicode 字符串是两个字节(char),这就是发生这种情况的原因。如果我这样做:

result = unistring[:2]

我明白了

M

这是正确的, 那么,我应该总是 slice*2 还是应该转换成什么?

【问题讨论】:

  • 你确定你有一个实际的 unicode 字符串,而不是(比如说)一个带有 UTF-8 数据的字节串吗?如果是这样,你如何定义“性格”? (unicode 字符串是代码点(在 UCS-4 构建中)或代码单元的字符串。)
  • 请不要。这在这里并不适用。
  • 其实是这样。 OP 显然对 unicode 和 UTF-8 感到困惑。

标签: python unicode python-2.x


【解决方案1】:

不幸的是,由于 Python 3.0 之前的历史原因,有两种字符串类型。 byte strings (str) and Unicode strings (unicode)

在 Python 3.0 统一之前,有两种方法可以声明字符串文字:unistring = "Μεταλλικα" 是字节字符串,unistring = u"Μεταλλικα" 是 unicode 字符串。

您在执行result = unistring[:1] 时看到? 的原因是您的Unicode 文本中的某些字符无法在非Unicode 字符串中正确表示。如果您曾经使用过非常旧的电子邮件客户端并收到来自希腊等国家/地区的朋友的电子邮件,您可能已经遇到过此类问题。

所以在 Python 2.x 中,如果您需要处理 Unicode,您必须明确地进行处理。看看这篇关于在 Python 中处理 Unicode 的介绍:Unicode HOWTO

【讨论】:

  • "Μεταλλικα" 不是 ASCII 字符串。它是用于保存脚本的编码中的字节字符串。
  • 你是对的标记将这些称为字节字符串而不是 ASCII 字符串更正确,我已经相应地更新了答案。我真正想表达的是 ASCII 文本(或等效的字节字符串,取决于您计算机上的代码页)是唯一可以使用字节字符串安全操作的内容。
【解决方案2】:

当你说:

unistring = "Μεταλλικα" #Metallica written in Greek letters

没有 unicode 字符串。您在(大概)UTF-8 中有一个字节串。那不是一回事。 Unicode 字符串是 Python 中的一种单独的数据类型。您可以通过使用正确的编码解码字节串来获得 unicode:

unistring = "Μεταλλικα".decode('utf-8')

或者在源文件中使用带有正确编码声明的 unicode 文字

# coding: UTF-8
unistring = u"Μεταλλικα"

当您执行unistring[:5] 时,unicode 字符串将执行您想要的操作。

【讨论】:

  • 在 Python 2.5 及更高版本中,您需要在任何具有非 ASCII 内容的源文件上进行编码声明,是的。 (在此之前它只是一个警告。)然而,编码声明不会改变代码的含义,因为它只是字节串中的字节。
  • -1 This is not correct u"Some Unicode test"[:5] 可能给出非法序列,因为 UTF-16 是可变宽度编码,所以切割“Unicode”字符串与切割 utf 不正确-8 字符串
  • 您似乎对 UTF-16 和 Unicode 感到困惑。 Python 仅在 UCS-2 构建中将 UTF-16 用于 Unicode(这主要是在 Windows 上)。在 UCS-4 构建中,切片 unicode 工作正常(这就是您应该使用 UCS-4 构建的原因。)。在 UCS-2 版本中,它适用于任何 BMP 字符,这是 OP 使用的。
  • 默认情况下,Python 是使用 UCS-2 构建的,即使在 linux 上也是如此。我知道可以使用 UCS-4 构建,但它们并不常见。因此,无论如何假设字符串可以“按原样”剪切是错误的。除非你只在 BMP 中工作。无论如何,这是错误的做法。原因请参见下面我的回答。
  • 默认是 UCS-2,但实际上大多数 linux 发行版都使用 UCS-4。只需查看典型系统上的 sys.maxunicode 即可。当使用 UCS-2 构建和非 BMP 字符时,无论如何都没有好的切片方法。
【解决方案3】:

对于任何类型的“Unicode 字符串”都没有正确的直接方法。

即使 Python "Unicode" UTF-16 字符串也有可变长度的字符,所以你不能只用 ustring[:5] 进行剪切。因为某些 Unicode 代码点可能使用多个“字符”,即代理对。

因此,如果您想删减 5 个代码点(注意这些不是字符)以便分析文本,请参阅http://en.wikipedia.org/wiki/UTF-8http://en.wikipedia.org/wiki/UTF-16 定义。所以你需要使用一些位掩码来找出边界。

而且你仍然没有得到字符。因为例如。单词“שָלוֹם”——希伯来语中的和平“Shalom”由 4 个字符和 6 个代码点字母“shin”、元音“a”字母“lamed”、字母“vav”和元音“o”以及最后一个字母“mem”组成。

所以 character 不是 code point

对于大多数西方语言也是如此,其中带有变音符号的字母可以表示为两个代码点。搜索例如“unicode normalization”。

所以...如果您真的需要 5 个第一个字符,您必须使用 ICU 库之类的工具。例如,Python 的 ICU 库提供了字符边界迭代器。

【讨论】:

    猜你喜欢
    • 2012-03-11
    • 2014-02-19
    • 2021-12-17
    • 1970-01-01
    • 2021-12-09
    • 2021-10-16
    • 1970-01-01
    • 1970-01-01
    • 2011-12-04
    相关资源
    最近更新 更多