1

我正在尝试使用正则表达式在后来出现的 groupB 中查找早期 groupA 中不存在的内容。如果它存在于 A 中,但不存在于 B 中,这很好。这似乎意味着如果我必须使用正则表达式,则必须进行否定的后视。

大量简化的示例:

文本:

groupA:
tag 789
tag 123

groupB:
Item 1:
... 123
... 456

我对环视很陌生。这是立即想到的(或十几种变体之一),但你们中的知情人士会发现它没有按预期工作。

regex:(\.\.\. (?<ID>(\d+)))(?<=(?s).*?tag (\k<ID>))

我的理想目标是匹配 groupB 中不存在于 groupA 中的项目,并且我无法重新排序输入。正确的示例输出:(不是由提供的正则表达式完成)

... 456

.NET 支持可变回溯距离,但显然我遗漏了一些东西!

4

2 回答 2

2

.NET 正则表达式引擎从左到右解析字符,因此您不能从右到左反向引用。当你到达B组时,A组中的所有角色都已经被消耗并且无法匹配。虽然正则表达式可能看起来回溯,但它实际上是预匹配或分支- 解析器永远不会向后运行。

使用正向运行的解析器,您需要首先匹配(并保留)A 组中的项目,然后只返回 B 组中不存在于 A 组中的项目。这对于确定性有限自动化来说太复杂了计算,因为它不能在恒定空间中完成。

可以通过反转字符串并向后运行匹配项来使用正则表达式来解决您的问题,但是代码可能会变得非常难以理解:

321 ...
:1 metI
:Bpuorg

321 gat
987 gat
:Apuorg

"((?<id>\d+)(?=\s\.\.\.))(?!.*\k<id>\sgat)"

结果:

"654"

相反,我建议通过以下方式保持简单:

var groupA = Regex.Matches(text, @"(?<=tag\s)\d+").Cast<Match>().Select(x => x.Value);
var groupB = Regex.Matches(text, @"(?<=\.\.\.\s)\d+").Cast<Match>().Select(x => x.Value);

var bNotA = groupB.Except(groupA);
于 2012-08-07T03:20:35.703 回答
0

我知道这是一个非常古老的问题,您自己可能不再对解决方案感兴趣,但我发现现有答案具有误导性,并想提供另一个答案。(另一个答案中的最终解决方案非常适合给定的问题 - 您不需要使用单个正则表达式来解决所有问题。但您的答案中指出的问题实际上并不是问题。)

您的想法实际上是正确的,但实施不正确。第一个问题是您正在使用积极的后视,这将确保之前出现过相同的。你想要的是消极的向后看,(?<!...)以确保该值没有出现。

然而,主要问题是您的后视内容的顺序是错误的。在您的代码中,您首先拥有通配符.*?然后是您想要匹配的东西tag (\k<ID>)。但是您正在寻找当前位置左侧tag X的某个位置,这意味着通配符实际上需要排在第二位。在后面看,正则表达式引擎的当前位置(在后面的外部)位于内部模式的末尾。想象一下做。这匹配in但不匹配 in 。(更重要的是,如果一定要走在前面,为什么自己不倒过来呢?(?<=abc)defdefabcdefcbadef.*?tag (\k<ID>)(\k<ID> gat)

所以这工作得很好:

(\.\.\. (?<ID>(\d+)))(?<!(?s)tag (\k<ID>).*?)

尽管它的组比您实际需要的多得多。这就足够了:

\.\.\. (?<ID>\d+)(?<!(?s)tag \k<ID>.*?)

在这里测试一下。

至于 Simon 的评论“.NET 正则表达式引擎从左到右解析字符,所以你不能从右到左反向引用。” 我不知道那件事。我还没有看到 regex 引擎的代码,但是从多年试验 .NET 的 regex 风格并将其滥用于各种恶作剧中,我可以说它肯定会像你所期望的那样回溯到所有实际目的。(他链接到的更快的算法只适用于不使用反向引用的模式,结果完全无法区分。)模式从左到右匹配,是的。但是,直到您实际到达模式中的后视后才会处理后视,并且它可以反向引用较早的捕获,即使这些在匹配的后期结束。

对此的两个警告是 a) .NET 具有从右到左的匹配模式,该模式实际上从右到左处理模式,因此捕获必须出现代码中的反向引用之后,并且 b) 后视使用所述从右到-left 模式(不幸的是,这是未记录的),因此引擎实际上可以通过使用正常的从左到右模式中的后视(或从右到左模式中的前瞻,或内部前瞻)来回编织输入字符串向后看,什么不是,但这可能不是您想在生产代码中使用的东西)。

在考虑反向引用何时有效以及何时无效时,这种处理输入的方向始终很重要。

于 2016-02-16T14:44:51.960 回答