正则表达式中的双重负回头
本文关键字:回头 正则表达式 | 更新日期: 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