在正则表达式中双重负面观察

时间:2015-06-16 17:52:41

标签: c# regex

我在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

外部负面后卫说&#34;字符串不能以[<some_id_here>] =&#34;开头。内部前瞻表示&#34;此字符串可以匹配除person_id之外的任何内容。我认为双重否定意味着&#34;如果此字符串前面有[<some_id_here>] =<some_id_here>必须只有person_id

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

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

这是我的regex101 link和我的测试用例。

3 个答案:

答案 0 :(得分:3)

由于你过滤掉整行,因此更容易:如果你发现任何你不想要的东西,你就可以抛弃它。

如果你正在使用PCRE,你可以使用回溯动词来达到你想要的目的:

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

Demo

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

在C#中,您没有(*SKIP)(*FAIL),因此您可以使用此代码:

(*SKIP)(*FAIL)

检查\bblob_id\b.+|(?<id>\b123\b) 。如果它是假的,扔掉比赛。

但C#中最好的选择是来使用可变长度的lookbehinds(C#正则表达式引擎的一个很棒的功能):

match.Groups["id"].Success

Demo

我在匹配之后将断言仅用于优化,因此引擎只有在已成功匹配\b123\b(?<!\bblob_id\b.*) 时才会实际检查后备。

看起来我误解了这个问题:

  

在您的第二个演示中,它过滤掉的唯一\b123\b<some_id_here>。我需要它来过滤掉任何不是blob_id的ID。

那么,在这种情况下,您需要放回那些括号来说明ID和其他内容。我想我可以使用它们,因为你在你的问题中做到了这一点。那么双重负面看起来是有道理的:

person_id

Demo

\b123\b(?<!\[(?!person_id\b)\w+\][^\]\n]*) 表示[^\]\n]和换行符之外的任何字符,因此您只能获得与搜索到的值最接近的标识符。

答案 1 :(得分:1)

问题是(?!person_id)与任何字符都不匹配。你可以做的是在负面观察中使用负面的背后隐藏来消除实际消费负面背后的任何东西的需要。

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

Demo

答案 2 :(得分:1)

这可能会更清楚地解释发生了什么,以及
如何添加确定 Id的列表,同时排除其中的其他ID 您已定义的括号格式。

编辑 - 做断言的提示 断言是自包含的结构。他们独立于行动 另一个。断言不知道他们是否在其他内部 断言。给予他们的位置是当前位置
相对到呼叫者,可能与 outter最多不同 当前位置。

最后,在断言中,断言是什么并不重要 表达式强制匹配..这是主要规则 该匹配的成功或失败在逻辑上被解析为类型 这是断言,即。消极/积极的结果。

@"(?<!\[(?!(?: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