使用通配符的正则表达式负向回顾先行断言

9

我正在尝试匹配一些文本,如果它在附近没有另一个文本块,则匹配成功。例如,如果"foo"不在"bar"之前出现,我想要匹配"bar"。我可以使用这个正则表达式中的负向后顾断言来匹配"bar",如果"foo"没有立即出现:

/(?<!foo)bar/

但我也希望不匹配"foo 12345 bar"。我尝试了:

/(?<!foo.{1,10})bar/

使用通配符和范围似乎在Ruby中不是一个有效的正则表达式。我对这个问题的思考方式有误吗?
2个回答

13

你的想法是正确的。但不幸的是,回溯断言通常需要固定长度。唯一的主要例外是.NET的正则表达式引擎,它允许在回溯断言内使用重复量词。但由于你只需要负向回溯断言而不是正向回溯断言,所以有一个技巧可供你使用。反转字符串,然后尝试匹配:

/rab(?!.{0,10}oof)/

如果您想要的是将匹配位置从字符串长度中减去,那么请对匹配结果进行反转或减法操作。

根据您提供的正则表达式,我推测这只是您实际所需的简化版本。当然,如果bar本身就是一个复杂模式,那么需要更多的思考来正确地进行反转。

请注意,如果您的模式需要变长回顾和前瞻,那么解决这个问题会更加困难。此外,在您的情况下,可以将您的回顾拆分为多个可变长度回顾(因为您既没有使用+也没有使用*):

/(?<!foo)(?<!foo.)(?<!foo.{2})(?<!foo.{3})(?<!foo.{4})(?<!foo.{5})(?<!foo.{6})(?<!foo.{7})(?<!foo.{8})(?<!foo.{9})(?<!foo.{10})bar/

但这还不太好,是吗?


1
反转字符串是一个有趣的想法。谢谢! - Kevin Eder

4
如m.buettner所提到的,Ruby正则表达式中的向后查找必须是固定长度,并在文档中有所描述。因此,您不能在向后查找中放置量词。
您不需要一步检查所有内容。尝试使用多个正则表达式匹配步骤来获取所需内容。假设无论是否存在另一个“bar”,在单个“bar”前面存在“foo”都会打破条件,则:
string.match(/bar/) and !string.match(/foo.*bar/)

以下是需要翻译的内容:

将为您提供所需的示例。

如果您希望匹配成功的字符串为bar foo bar,则可以使用以下方法:

string.scan(/foo|bar/).first == "bar"

如果想要实际检索匹配项,那就有问题了。比如你有一个字符串 bar foo bar。原帖中尝试的正则表达式会检索到第一个 bar。而你的解决方案则会认为没有匹配项。(除了你忽略了“最多10个字符”的启发式算法这一事实) - Martin Ender
@m.buettner,你和我对这个问题的理解不同。 - sawa
1
当然。这就是为什么我不会说你的解决方案是错误的。但我认为重要的是要说明这样的假设和差异。因为对于未来的提问者或其他人来说,这些可能并不明显。 - Martin Ender
感谢您阐述不同的解释。我接受@m.buettner的回答,因为这正是我所需要的。 - Kevin Eder

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接