正则表达式跳过不必要的所有格

时间:2018-12-22 04:15:20

标签: python regex

我有一个字符串

aaaa bbbb cccc=v1

我要捕获cccc = v1(field_value对,而不是确切的“ cccc”)。 为了提高性能,我使用了原子组,以便在找不到=时不浪费时间回溯

\b[^\s=]++=\w+

但是发生的事情是即使它没有回溯,它也会像下面那样检查字符串中的每个字符

aaaa bbbb cccc=v1
^
aaaa bbbb cccc=v1
 ^
aaaa bbbb cccc=v1
  ^
aaaa bbbb cccc=v1
   ^

在这种情况下,当未捕获原子组时,我可以跳过匹配吗? 像这样

aaaa bbbb cccc=v1
^
aaaa bbbb cccc=v1
     ^
aaaa bbbb cccc=v1
          ^

我认为它绝对可以提高性能。

2 个答案:

答案 0 :(得分:2)

一次匹配一个非=单词中所有字符的 all 的一个选项是在模式的开头使用(?:\w+ )*。 (如果不能保证=单词,请使其占有所有,以防止回溯。)然后,使用\K忘记先前匹配的文本,然后将=单词与{{ 1}}:

[^\s=]++=\w+

https://regex101.com/r/RVogoh/5

尽管如此,当要搜索的整个字符串较小时-与原始字符串相比,只有63个步长,这只是适度的改进

https://regex101.com/r/RVogoh/1/

需要90步。仅当有许多字符时,此实现才比原始的逐字符测试显着提高效率。

请注意,^(?:\w+ )*+\K[^\s=]+=\w+ 模块不支持\K-为此,您必须使用pypi的re模块。

答案 1 :(得分:0)

已更新

我认为您会发现,在行尾找到key=value对时,大部分明智的正则表达式将具有合理的性能。 (即使是长行和部分匹配。)

以下是一些时间安排。我使用了this SO post中的cmpthese函数来比较相对计时:

import re 
import regex 

def f1():
    # re from my comment
    return re.findall(r'(?<=[ ])(\w+=\w+)$', txt, flags=re.M)

def f2():
    # the OP's regex
    return regex.findall(r'\b([^\s=]++=\w+)', txt, flags=re.M)

def f3():
    # alternate regex 
    return re.findall(r'(\w+=\w+)$', txt, flags=re.M)   

def f4():
    # CertainPerformance updated regex
    return regex.findall(r'^(?:\w+ )*+\K[^\s=]+=\w+', txt, flags=regex.M)   

def f5():
    return [line.split()[-1] for line in txt.splitlines() if re.match(r'^(\w+=\w+)$', line.split()[-1])]    

txt='''\
a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a bc d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d e=
aaaa bbbb cccc=v1
aaaa bbbb cccc
aaaa bbbb cccc=v1
'''*1000000


cmpthese([f1,f2,f3,f4,f5],c=3)  

此代码在Python 2上打印(最慢显示在顶部,最快显示在底部):

   rate/sec    usec/pass     f2     f4     f1     f3     f5
f2        0 36721115.669     -- -27.2% -72.0% -72.0% -77.5%
f4        0 26715482.632  37.5%     -- -61.4% -61.5% -69.0%
f1        0 10300210.953 256.5% 159.4%     --  -0.0% -19.6%
f3        0 10296802.362 256.6% 159.5%   0.0%     -- -19.6%
f5        0  8280366.262 343.5% 222.6%  24.4%  24.4%     --

和Python 3:

   rate/sec    usec/pass     f2     f4     f3     f1     f5
f2        0 40880883.330     -- -42.3% -64.4% -70.3% -78.3%
f4        0 23592684.768  73.3%     -- -38.4% -48.6% -62.3%
f3        0 14544536.920 181.1%  62.2%     -- -16.6% -38.9%
f1        0 12131648.781 237.0%  94.5%  19.9%     -- -26.7%
f5        0  8888514.997 359.9% 165.4%  63.6%  36.5%     --

我相信f2f4的慢速性更可能是通过使用regex模块而不是re模块来实现的,但是这些函数中的正则表达式需要使用{{ 1}}模块。苹果与苹果比较之下,regex中的正则表达式应该很快。

您可以看到,使用f4模块,在锚点后面稍微添加外观可以提高速度。 re模块很可能是regex比其他模块慢的罪魁祸首。从理论上讲,例如f4中的正则表达式更快。<​​/ p>


注释和“性能评估”仅关注regex101中的“步骤”数。这是不同正则表达式表达的相对性能的不完整描述。 Regex101在完成正则表达式所需的时间上也具有Perl等级-这取决于服务器的土地。某些正则表达式步骤比其他步骤更快。

考虑正则表达式ms在regex101 in this example中,运行它需要205个步骤和约2ms。

现在考虑(?<=[ ])的{​​{3}},它需要83个步骤,但要运行大约2ms。

现在考虑使用[ \t]中的更多simpler regex,尽管它需要405步,但运行时间却延长了将近5倍。

尽管(\w+)\1\b是正则表达式速度的指标,但并不是每个步骤都花费相同的时间来执行。您还需要查看总执行时间。