正则表达式中的双重负回头

本文关键字:回头 正则表达式 | 更新日期: 2023-09-27 17:56:29

我正在过滤掉SQL脚本中包含某些人员ID的行。 就我的目的而言,在我的过滤中过分热心比在过滤中过分热心要好,但我仍然想小心一点。

例如,如果其中一个人员 ID 是 123 ,并且一行包含 [blob_id] = 123 ,我不想过滤掉它。 所以,我想找到123(两侧都有单词分隔符),只要它前面没有[<some_id_here>] =,或者<some_id_here> = person_id .

正则表达式应与以下每一行匹配:

123
[person_id] = 123
blah,blah,123,blah

它不应该与以下每一行匹配:

foo123bar
[blob_id] = 123

我认为这个正则表达式会起作用:

(?<!'[(?!person_id)'] = )'b123'b

外部负视后说"字符串前面不能有[<some_id_here>] ="。 内部展望说:"这个字符串可以匹配除person_id以外的任何东西。 我认为双重否定意味着"如果这个字符串前面有 [<some_id_here>] =<some_id_here>只能是person_id

不幸的是,情况似乎并非如此。 它适用于我除[blob_id] = 123以外的所有测试用例。

我相信正在发生的事情是,出于某种原因,由于双重否定,外部的后视与任何东西相匹配。

这是我的正则表达式101与我的测试用例的链接。

正则表达式中的双重负回头

由于您要过滤掉整行,因此更容易:如果您在一行中找到任何不想要的内容,则可以丢弃该行。

如果您使用的是PCRE,则可以使用回溯动词来实现您想要的:

'bblob_id'b.+(*SKIP)(*FAIL)|'b123'b

演示

如果正则表达式引擎在一行上遇到blob_id,它将匹配直到行尾(.+),然后匹配失败,并在失败的位置重新尝试((*SKIP)(*FAIL))。这是有效的,因为引擎总是从左到右尝试替代方案。


在 C# 中,您没有 (*SKIP)(*FAIL) ,因此您可以改用它:

'bblob_id'b.+|(?<id>'b123'b)

检查match.Groups["id"].Success。如果是假的,就把火柴扔掉。

但是 C# 中最好的替代方案是...使用可变长度的回溯(C# 正则表达式引擎的一个重要功能):

'b123'b(?<!'bblob_id'b.*)

演示

我将断言放在匹配之后只是为了优化,因此引擎只有在已经成功匹配'b123'b时才实际检查回溯。


看来我误解了这个问题:

在您的第二个演示中,它过滤掉的唯一<some_id_here>blob_id .我需要它来过滤掉任何不person_id 的 id。

好吧,在这种情况下,您需要放回这些括号以判断什么是 ID 和其他内容。我想我可以利用它们,因为你在你的问题中正是这样做的。那么双重否定的环顾是有道理的:

'b123'b(?<!'[(?!person_id'b)'w+'][^']'n]*)

演示

[^']'n] 表示]和换行符之外的任何字符,因此您只能获得最接近搜索值的标识符。

问题是(?!person_id)与任何字符都不匹配。相反,您可以做的是在负面回溯中使用负面回溯,以消除在负后视中实际消耗任何东西的需要。

(?<!(?<!'[person_id)'] = )'b123'b

演示

这可能会更

清楚地解释正在发生的事情,并且
如何在排除其他 ID 时添加 OK ID
的列表已定义的括号格式。

编辑 - 执行断言的提示。
断言是自包含构造。他们独立于
彼此。断言不知道它们是否在其他内部
断言。给他们的位置是当前的位置
相对于调用方,这可能与外部最
不同当前位置。

最后,断言是什么并不重要,在

断言中,
表达式被迫匹配..这是主要规则。
该匹配的成功或失败在逻辑上解析为
断言它是,即。阴性/阳性结果。

@"(?<!'[(?!(?:person_id|ok_id)'])[^']]+']'s*='s*)'b123'b"

 .*                      # For testing purposes, get whole line before
 (?<!                    # Bracket ID's can't be behind the '123'
      '[                      # Open bracket [
      (?!                     # Exclude ID's that are OK to be here
           (?:
                person_id               # this id is OK
             |  ok_id                   # this id is OK (add more here, etc..)          
           )
           '] 
      )
      [^']]+                  # 1 or more id chars
      ']                      # Close bracket ]
      's*                     # Optional whtiespace
      =                       # Equals sign
      's*                     # Optional whtiespace
 )
 'b 123 'b 
 .*                      # For testing purposes, get whole line after

代码片段:

string input = @"
123
[person_id] = 123
blah,blah,123,blah
foo123bar
[blob_id] = 123
";
Regex Rx123 = new Regex(@".*(?<!'[(?!(?:person_id|ok_id)'])[^']]+']'s*='s*)'b123'b.*");
Match _m = Rx123.Match( input );
while (_m.Success)
{
    Console.WriteLine("Found: {0}", _m.Groups[0].Value);
    _m = _m.NextMatch();
}

输出:

Found: 123
Found: [person_id] = 123
Found: blah,blah,123,blah