如何优化此正则表达式以获得更好的性能?

时间:2020-11-07 13:43:55

标签: .net regex negative-lookbehind

我正在尝试优化.NET应用的正则表达式之一。

正则表达式:(?<!WordA\s(?:WordB\s)?)(WordB\s)?WordC

逻辑:

  • 找到匹配的WordC
  • 加入WordB进行匹配(如果在WordC之前出现)
  • 如果WordC位于WordA之前,则不匹配任何内容(即使由WordB开头)

应该匹配:

  • WordC
  • WordB WordC

不匹配:

  • WordA WordC
  • WordA WordB WordC

该表达式有效,但是如您所见,WordB在该表达式中出现了两次,所以我试图删除其中之一以获得更好的性能。

注意:“单词”实际上是复杂的表达式。

有什么办法吗?

1 个答案:

答案 0 :(得分:1)

“优化” (?<!WordA\s(?:WordB\s)?)(WordB\s)?WordC正则表达式(是(?<!WordA\s)WordC(?<!WordA\s)WordB\sWordC的组合)的问题在于,WordBWordC用空格,并且一旦后面有WordB WordC之前WordA,正则表达式后面的否定表达式不会使正则表达式引擎跳过匹配的短语,因此仅跳过失败的位置,因此如果满足以下条件,WordC将匹配您只需使用(?<!WordA\s)(WordB\s)?WordC。后向必须同时限制WordB\sWordCWordC,这就是为什么您必须在后向模式中重复可选的WordB的原因,与在上面显示的两个“变形”模式中使用它的方式相同

因此,使用纯字符串正则表达式,别无选择。

涉及一些代码更改的解决方法看起来像

var rx = @"(WordA\s)?(?:WordB\s)?WordC";
var strings = new List<String> {"WordC", "WordB WordC", "WordA WordC", "WordA WordB WordC"};
foreach (var s in strings)
{
    var m = Regex.Match(s, rx);
    Console.WriteLine("{0}: {1}", s, (m.Groups[1].Success ? "NO MATCH" : m.Value));
}
// => WordC: WordC
// => WordB WordC: WordB WordC
// => WordA WordC: NO MATCH
// => WordA WordB WordC: NO MATCH

请参见C# demo

(WordA\s)?(?:WordB\s)?WordC正则表达式中,(WordA\s)?捕获WordA,其中空白被捕获到组1中,如果匹配,我们就需要丢弃匹配。如果组1 .Success的值为 false ,则表示匹配有效。