不区分大小写的string在Python中开始

这里是我如何检查mystring是否以string开头:

 >>> mystring.lower().startswith("he") True 

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

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

我不成功的尝试:

 >>> import re; >>> mystring.startswith("he", re.I) False 

你可以使用正则expression式,如下所示:

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

在2000字符的string上,这比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 

如果您重复匹配相同的前缀,则预编译正则expression式可能会产生很大的不同:

 In [41]: p = re.compile('he', re.I) In [42]: %timeit p.match(s) 1000000 loops, best of 3: 351 ns per loop 

对于短前缀,在将string转换为小写字符之前将字串切分出来可能会更快:

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

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

在我的实验中,单独检查每个angular色可能会更快:

 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 

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

这个怎么样:

 prefix = 'he' if myVeryLongStr[:len(prefix)].lower() == prefix.lower() 

根据.lower()的性能,如果前缀足够小,多次检查相等性可能会更快:

 s = 'A' * 2000 prefix = 'he' ch0 = s[0] ch1 = s[1] substr = ch0 == 'h' or ch0 == 'H' and ch1 == 'e' or ch1 == 'E' 

计时(使用与NPE相同的string):

 >>> timeit.timeit("ch0 = s[0]; ch1 = s[1]; ch0 == 'h' or ch0 == 'H' and ch1 == 'e' or ch1 == 'E'", "s = 'A' * 2000") 0.2509511683747405 = 0.25 us per loop 

与现有方法相比:

 >>> timeit.timeit("s.lower().startswith('he')", "s = 'A' * 2000", number=10000) 0.6162763703208611 = 61.63 us per loop 

(当然,这太可怕了,但是如果代码对性能至关重要,那么这可能是值得的)

只要您考虑到ASCII范围之外的任何内容,所给出的答案都不是真的正确。

例如,在不区分大小写的比较中,如果您遵循Unicode的大小写映射规则,则应将其视为等于SS

为了得到正确的结果,最简单的解决scheme是安装遵循标准的Python 正则expression式模块:

 import re import regex # enable new improved engine instead of backwards compatible v0 regex.DEFAULT_VERSION = regex.VERSION1 print(re.match('ß', 'SS', re.IGNORECASE)) # none print(regex.match('ß', 'SS', regex.IGNORECASE)) # matches