不区分大小写的字符串以Python开头

Nic*_*oul 42 python string performance startswith case-insensitive

以下是我如何检查是否mystring以某个字符串开头:

>>> mystring.lower().startswith("he")
True
Run Code Online (Sandbox Code Playgroud)

问题是mystring很长(数千个字符),所以lower()操作需要很多时间.

问题:有更有效的方法吗?

我不成功的尝试:

>>> import re;
>>> mystring.startswith("he", re.I)
False
Run Code Online (Sandbox Code Playgroud)

NPE*_*NPE 48

您可以使用正则表达式,如下所示:

In [33]: bool(re.match('he', 'Hello', re.I))
Out[33]: True 

In [34]: bool(re.match('el', 'Hello', re.I))
Out[34]: False 
Run Code Online (Sandbox Code Playgroud)

在2000个字符的字符串上,这比lower()以下快20倍:

In [38]: s = 'A' * 2000

In [39]: %timeit s.lower().startswith('he')
10000 loops, best of 3: 41.3 us per loop

In [40]: %timeit bool(re.match('el', s, re.I))
100000 loops, best of 3: 2.06 us per loop
Run Code Online (Sandbox Code Playgroud)

如果您重复匹配相同的前缀,预编译正则表达式会产生很大的差异:

In [41]: p = re.compile('he', re.I)

In [42]: %timeit p.match(s)
1000000 loops, best of 3: 351 ns per loop
Run Code Online (Sandbox Code Playgroud)

对于简短的前缀,在将字符串转换为小写之前将字符串切除,可能会更快:

In [43]: %timeit s[:2].lower() == 'he'
1000000 loops, best of 3: 287 ns per loop
Run Code Online (Sandbox Code Playgroud)

这些方法的相对时间当然取决于前缀的长度.在我的机器上,盈亏平衡点似乎是六个字符,这是预编译的正则表达式成为最快的方法.

在我的实验中,分别检查每个字符可能更快:

In [44]: %timeit (s[0] == 'h' or s[0] == 'H') and (s[1] == 'e' or s[1] == 'E')
1000000 loops, best of 3: 189 ns per loop
Run Code Online (Sandbox Code Playgroud)

但是,此方法仅适用于编写代码时已知的前缀,并且不适用于较长的前缀.

  • @BasicWolf:密钥在*"如果你重复匹配相同的前缀......"*.它的含义是编译成本(~900ns)在许多匹配中摊销并变得可以忽略不计. (2认同)

ins*_*get 25

这个怎么样:

prefix = 'he'
if myVeryLongStr[:len(prefix)].lower() == prefix.lower()
Run Code Online (Sandbox Code Playgroud)


Azi*_*lto 7

另一个简单的解决方案是将一个元组传递startswith()给所有需要匹配的情况,例如.startswith(('case1', 'case2', ..)).

例如:

>>> 'Hello'.startswith(('He', 'HE'))
True
>>> 'HEllo'.startswith(('He', 'HE'))
True
>>>
Run Code Online (Sandbox Code Playgroud)

  • 当两个字符串通常都来自外部源时,这在现实世界中不太可能发生...同时生成所有选项的效率极低(长度为 n 的字符串的 2^n 个选项) (2认同)