【问题标题】:Double negative lookbehind in regex正则表达式中的双重否定后视
【发布时间】:2015-06-16 17:52:41
【问题描述】:

我正在过滤 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

外部否定后视表示“字符串前面不能有[&lt;some_id_here&gt;] =”。内部前瞻表示“此字符串可以匹配除person_id 之外的任何内容。我认为双重否定意味着“如果此字符串前面有[&lt;some_id_here&gt;] =&lt;some_id_here&gt; 只能是person_id

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

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

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

【问题讨论】:

  • 您是否按照 regex101 链接的建议使用 PCRE?
  • 我不确定你的意思。在我的程序中使用它之前,我在网站上对其进行了测试,甚至在让它在那里工作时遇到了麻烦。
  • 换句话说:您使用什么语言?
  • 我将使用 C#。我想我刚刚找到了一个替代的正则表达式来完成我想要的。 ((?&lt;!\] = )|(?&lt;=\[person_id\] = ))\b123\b
  • 如果您查看我的回答,您就会明白为什么标记语言对于正则表达式问题真的很重要。如果我知道你预先使用 C#,我开始写一个完全不同的答案。 :-)

标签: c# regex


【解决方案1】:

由于您要过滤掉整行,所以更容易:如果您在一行中发现任何您不想要的内容,您可以将其丢弃。

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

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

Demo

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


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

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

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

但在 C# 中最好的替代方法是......使用可变长度的lookbehinds(C# 正则表达式引擎的一个很棒的特性):

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

Demo

我将断言放在匹配之后只是为了优化,所以引擎只会在它已经成功匹配\b123\b 的情况下实际检查后向。


看来我误解了这个问题:

在您的第二个演示中,它过滤掉的唯一 &lt;some_id_here&gt;blob_id。我需要它来过滤掉任何不是 person_id 的 id。

好吧,在这种情况下,您需要放回那些括号来说明什么是 ID,什么是其他东西。我想我可以利用它们,因为您在问题中正是这样做的。那么双重否定环顾是有意义的:

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

Demo

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

【讨论】:

  • 如果\b123\b 中的123 是与| 连接的665 个字符串,这是否仍然有效?还是创建 665 个 Regex 实例并运行它们会更好?或者更快地运行` if (string.Contains(myId) && myRegex.IsMatch(myIdRegex))`? (或者我应该测试一下?)
  • @dfoverdx 你应该只测试这个,就像所有与性能相关的问题一样 :-) 但你也可以尝试考虑 ID,比如不写 123|128|236|237|238 你可以写 12[38]|23[6-8]
  • 在您的第二个演示中,它过滤掉的唯一&lt;some_id_here&gt;blob_id。我需要它来过滤掉任何不是person_id 的ID。使用您的方法是否容易做到这一点,还是让它变得更复杂?
  • @dfoverdx 啊我误解了你的问题,我看到了......我已经更新了答案。
  • 不幸的是,我找到了一条应该匹配但不匹配的行。当另一个[ 在字符串中时似乎会发生这种情况。 DELETE FROM [dbo].[secu_login] WHERE [person_id] = 123
【解决方案2】:

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

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

Demo

【讨论】:

  • 有趣。所以问题是括号在内部前瞻的外面。
  • 对,你基本上是在说:“匹配[],但前提是右括号没有突然变成person_id
【解决方案3】:

这可能会更清楚地解释正在发生的事情,并且
如何添加 OK Id 列表同时排除其他 Id 在
您定义的括号格式。

edit - 进行断言的技巧。
断言是自包含的构造。他们独立于
另一个。断言不知道它们是否在 other
断言。给他们的位置是当前位置
相对调用者,它可能不同于最外层
当前位置。

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

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

代码sn-p:

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

【讨论】:

    猜你喜欢
    • 2011-12-07
    • 2017-04-20
    • 2014-04-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多