【问题标题】:.NET RegExp engine search performance optimization.NET RegExp 引擎搜索性能优化
【发布时间】:2009-04-29 10:51:58
【问题描述】:

我有大约 35,000 个字符串的 List 集合

典型的字符串如下所示:

"<i>füüs</i>ampri tähis;lüh ld-st<i>anno</i>, aastal;<i>maj</i> lüh pr-st<i>argent</i>, raha (kursisedelitel)"

基本上这个字符串包含一堆爱沙尼亚语的单词:)

我需要允许用户对 35,000 个字符串执行 RegExp 搜索

如果我使用 /ab.*/ 表达式执行搜索,则搜索时间不到一秒

如果我使用 /.*ab/ 表达式执行搜索,那么搜索大约需要 10 秒

我的问题是:如何使第二次搜索更快(少于 1.5 秒)?

非常感谢

【问题讨论】:

  • 您的用户需要完整的正则表达式搜索功能吗?
  • 所以 Daniil 看起来你会自己回答这个问题并将其标记为正确答案,就像你对大多数其他问题所做的那样:)
  • 这真是开玩笑,Binoj!我喜欢!

标签: c# .net regex performance optimization


【解决方案1】:

正则表达式的处理方式使它们的表现如此不同。根据您的示例进行解释:

  • /.*ab/   此表达式由两个子表达式组成,.* 和文字 ab。这将被处理如下:在正常的贪婪模式下,每个量词因此匹配被扩展到其最大值,.* 将首先匹配整个字符串。然后它将尝试匹配以下ab。但是因为不可能(我们已经在字符串的末尾),所以将使用回溯来找到两个子表达式匹配的最后一个点。因此.* 的匹配减少了一个字符,然后再次测试ab。如果整个表达式都匹配不上,再次匹配.*会减少一个字符,直到匹配整个表达式。在最坏的情况下,字符串中没有ab,算法将对ab 进行n+1 次回溯和额外测试,直到确定不可能匹配为止。

  • /ab.*/   这个表达式也包含两个子表达式。但是这里的顺序发生了变化,首先是文字ab,然后是.*。处理如下:算法首先尝试通过比较一个字符来找到文字ab。如果有匹配项,它会尝试为.* 找到匹配项,这显然很容易。

这两个正则表达式的主要区别在于,第二个正则表达式的开头是静态部分,结尾是可变部分。这样就不需要回溯了。

尝试一些正则表达式分析工具,例如RegexBuddy,以直观地查看差异。

【讨论】:

  • 确实很好的解释。 .*ab 表达式的另一个提示是将其更改为 ^.*ab。在某些情况下,如果结果相同,这会快很多倍。
【解决方案2】:

使用compiled regular expressions 以获得更好的性能

http://en.csharp-online.net/CSharp_Regular_Expression_Recipes—Compiling_Regular_Expressions

复制粘贴完整的网址,看来此链接存在渲染问题。

【讨论】:

  • 哇,它解决了我的部分问题。现在相同的搜索需要 2.5 秒
【解决方案3】:

对于慢速 .*ab 表达式,我可以建议两种可能的修改。

我使用 Regex Hero 中的基准测试功能,使用这个测试字符串“1234567890 ab 1234567890”执行了我的测试。

一个。比原来快 5 倍

^.*ab
RegexOptions.None

B。比原来快 8 倍

.*ab
RegexOptions.RightToLeft

有时实验会有所回报。 RightToLeft 选项是我的“啊哈!”片刻。通过防止发生大规模回溯,这基本上返回了与您的其他 ab.* 表达式相同的性能。

【讨论】:

  • +1。是的,我认为RightToLeft 选项并没有得到应有的关注。
  • Compiled 选项在 Silverlight 中不可用,否则我也会使用它。但是,是的,RightToLeft 选项基本上解决了这种情况下的整个回溯问题。
【解决方案4】:

我有一个疯狂的想法,如果用户输入 /.*ab/,您也可以以相反的顺序存储字符串并使用 /ba.*/ 搜索这些字符串。

【讨论】:

  • 但是反转 35,000 个目标字符串需要多长时间? ;)
【解决方案5】:

您的第二个表达式将匹配 'ab' 及其之前的所有字符(新行除外)。您可以尝试仅搜索 /ab/,获取匹配项的索引,然后将匹配项之前的字符串部分与 match 连接起来。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-05-14
    • 2011-08-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多