【问题标题】:Python 3 string index lookup is O(1)?Python 3 字符串索引查找是 O(1)?
【发布时间】:2017-05-01 13:51:33
【问题描述】:

短篇小说:

Python 3 unicode 字符串查找是 O(1) 还是 O(n)?

长篇大论:

在 C 字符数组中查找字符的索引是常数时间 O(1),因为我们可以确定地跳转到一个连续的内存位置:

const char* mystring = "abcdef";
char its_d = mystring[3];

和说的一样:

char its_d = *(mystring + 3);

因为我们知道sizeof(char) 在 C99 中是 1,并且由于 ASCII 的原因,一个字符适合一个字节。

现在,在 Python 3 中,字符串文字是 unicode 字符串,我们有以下内容:

>>> mystring = 'ab€cd'
>>> len(mystring)
5
>>> mybytes = mystring.encode('utf-8')
>>> len(mybytes)
7
>>> mybytes
b'ab\xe2\x82\xaccd'
>>> mystring[2]
'€'
>>> mybytes[2]
226
>> ord(mystring[2])
8364

采用 UTF-8 编码,字节 2 > 127,因此对字符 3 使用多字节表示。

由于字符的多字节表示,我只能得出结论,Python 字符串中的索引查找不能是 O(1)?这意味着mystring[2] 是 O(n),并且以某种方式正在执行内存数组的即时解释以查找索引处的字符?如果是这样的话,我是否错过了一些说明这一点的相关文档?

我做了一些非常基本的基准测试,但我无法推断出 O(n) 行为:https://gist.github.com/carlos-jenkins/e3084a07402ccc25dfd0038c9fe284b5

$ python3 lookups.py
Allocating memory...
Go!
String lookup: 0.513942 ms
Bytes lookup : 0.486462 ms

编辑:用更好的例子更新。

【问题讨论】:

  • 177 大于127,但小于255
  • 字符串的内部表示不必是 UTF-8。
  • >>> ord(mystring[3]) 233 >>> ord(mystring[2]) 241 >>> ord(mystring[4]) 98,均低于255
  • “在 ASCII 中,一个字符与一个字节相同”——这是不正确的。 C ** 指定 char 正好是一个字节。 ASCII 是 7 位代码,因此 ASCII 字节将是 7 位,这在 C 中是不允许的。C 也没有要求特定的编码,只是最小字符集。

标签: python utf-8


【解决方案1】:

UTF-8 是 Python 的默认 source 编码。 The internal representation uses fixed-size per-character elements 在 Python 2 和 Python 3 中。结果之一是通过索引访问 Python (Unicode) 字符串对象中的字符需要 O(1) 成本。

您提供的代码和结果并未另行说明。您将 string 转换为 UTF-8 编码的字节序列,我们都知道 UTF-8 使用可变长度的代码序列,但这些都没有说明原始 string 的内部表示。

【讨论】:

  • 我错误地认为 unicode 字符串的内部表示是 UTF-8 字节编码的字节数组。谢谢你的解释!
  • 如果字符可以任意长,怎么能是固定大小的呢?例如。 “?‍?‍?‍?”是 5 个代码点(男人 + 零宽度细木工 + 女人 + 女孩 + 男孩)。您无法将其放入单个 8、16 或 32 位元素中
  • @Alexander-ReinstateMonica,Unicode 字符不是任意长。每一个都是一个字符长,每个字符对应一个从 21 位代码空间中抽取的数字。甚至像 UTF-8 这样的可变长度编码也提供 有界 长度的字符表示。单个 Unicode 字符的有效 UTF-8 编码不超过四个字节。我认为您无法区分单个字符和字符串。
  • @JohnBollinger 通过“字符”,我指的是用户感知的字符,或者 Unicode 将其称为遗留字素簇或扩展字素簇,例如上面的家庭表情符号。就用户而言,它是单个字符,以及单个扩展字素簇,由 5 个单独的代码点(男人、细木工、女人、女孩、男孩)组成。似乎 python 3 的字符串下标具有引用代码点的索引,而不是字符。所以"?‍?‍?‍?"[0] 给出了"?",而不是完整的家庭角色
  • 我觉得这真的很奇怪,因为 Python 是一种高级语言。单个代码点就像实现细节,我不知道为什么索引字符串会产生代码点,这使得字符串操作很容易导致无效结果。您很容易在无意中做出导致无效排序的更改,例如删除"ïabc" 的第一个字母会导致0x0308 重音不在字符后(因此没有重音)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-10-02
  • 2020-08-04
  • 1970-01-01
  • 1970-01-01
  • 2018-01-22
相关资源
最近更新 更多