带有通配符的正则表达式负向外观

时间:2012-11-30 19:15:55

标签: ruby regex lookbehind

我正在尝试匹配一些文本,如果它附近没有另一个文本块。例如,如果"bar"不在"foo"之前,我想匹配"bar"。我可以匹配"foo"如果/(?<!foo)bar/ >

"foo 12345 bar"

但我也想不匹配/(?<!foo.{1,10})bar/ 。我试过了:

{{1}}

但使用通配符+范围似乎是Ruby中的无效正则表达式。我在想这个问题错了吗?

2 个答案:

答案 0 :(得分:12)

你正在考虑正确的方法。但不幸的是,后视镜通常具有固定长度。唯一的主要例外是.NET的正则表达式引擎,它允许在lookbehinds内部重复量词。但是,因为你只需要一个消极的外观,而不是前瞻。有一个黑客为你。反转字符串,然后尝试匹配:

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

然后反转匹配的结果或从字符串的长度中减去匹配的位置,如果这就是你所追求的。

现在从你给出的正则表达式,我想这只是你真正需要的简化版本。当然,如果bar本身就是一个复杂的模式,那么需要更多考虑如何正确地反转它。

请注意,如果您的模式需要可变长度的lookbehinds和lookaheads,那么解决这个问题会更难。此外,在您的情况下,可以将您的lookbehind解构为多个可变长度的(因为您既不使用+也不使用*):

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

但那不是那么好,是吗?

答案 1 :(得分:3)

正如m.buettner已经提到的,Ruby正则表达式中的lookbehind必须具有固定的长度,并在文档中进行了描述。所以,你不能把量词放在后面。

您无需一步检查所有内容。尝试执行多个正则表达式匹配步骤以获得所需内容。假设在foo的单个实例前面存在bar会破坏条件,无论是否有另一个bar,那么

string.match(/bar/) and !string.match(/foo.*bar/)

将为您提供您想要的示例。

如果您希望匹配在bar foo bar成功,那么您可以执行此操作

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