9

如果附近没有另一块文本,我正在尝试匹配一些文本。例如,我想匹配"bar"if"foo"不在它之前。我可以在此正则表达式中使用否定查找来匹配"bar"if"foo"立即在它之前:

/(?<!foo)bar/

但我也喜欢不匹配"foo 12345 bar"。我试过:

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

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

4

2 回答 2

13

你正在以正确的方式思考它。但不幸的是,lookbehinds 通常是固定长度的。唯一的主要例外是 .NET 的正则表达式引擎,它允许在lookbehinds 中使用重复量词。但是因为你只需要一个消极的向后看,而不是向前看。有一个 hack 适合你。反转字符串,然后尝试匹配:

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

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

现在从您给出的正则表达式来看,我想这只是您实际需要的简化版本。当然,如果bar是一个复杂的模式本身,需要更多的思考如何正确地反转它。

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

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

但这并不是那么好,不是吗?

于 2012-11-30T19:23:35.990 回答
4

正如 m.buettner 已经提到的,Ruby regex 中的lookbehind 必须具有固定长度,并且在文档中进行了描述。因此,您不能将量词放在后面。

您无需一步完成所有检查。尝试执行多个正则表达式匹配步骤以获得您想要的。假设foo在单个实例前面存在bar打破条件而不管是否存在另一个bar,那么

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

会给你你想要的例子。

如果您希望匹配成功bar foo bar,那么您可以这样做

string.scan(/foo|bar/).first == "bar"
于 2012-11-30T21:26:43.147 回答