Ruby 正则表达式:用新行捕获点,有条件地后跟另一个表达式

Ruby regex: Capturing dot with new lines conditionally followed by another expression

我有一个多行字符串,我需要在其中捕获包含换行符的表达式,但最多只能捕获另一个可能存在也可能不存在的表达式。

示例字符串:

FOO
Hello
world
BAR
Hello

这里我想捕获"Hello world"(包括新行),我可以用

/FOO(.*)BAR/m

但是 BAR 可能在也可能不在字符串中。所以我倾向于让 BAR 成为一个非捕获组,? 可能不存在,例如:

/FOO(.*)(?:BAR)?/m

但这会捕获尾随的 BARHello。其他尝试包括仅为点指定 m 模式,如

/FOO(?m:(.*))(?:BAR)?/

但这会带来同样的问题。

对于那些慷慨帮助我的人,您可以使用 http://rubular.com/ 在 Ruby 中测试正则表达式。谢谢!

选项 1 - 否定前瞻

使 .* 匹配除 BAR 之外的任何内容。表达式:

(?:(?!BAR).)*

使用 negative lookahead 创建一种 循环 检查,在匹配每个字符之前,它后面没有跟 BAR

正则表达式

/FOO((?:(?!BAR).)*)/m

rubular demo


选项 2 - 惰性量词

您还可以使用 lazy quantifier .*? 使 .* 尽可能少地匹配(注意额外的 ?)。并要求表达式匹配 BAR\z 字符串的结尾。

正则表达式

/FOO(.*?)(?:BAR|\z)/m

rubular demo

$' The string following whatever was matched by the last successful pattern match

strs = [
  "",
  "FOO\nHello\nworld\nBAR\nHello",
  "FOOxxxBAR...FOOyyyBAR",
  "FOO\nHello\nworld\nHello",
  "FOOxxxxxxxFOOyyyBAR",
]

strs.each do |str|
  str.scan('FOO') do 
    p $'.split('BAR').first if $'
  end
end

--output:--
"xxx"
"yyy"
"\nHello\nworld\nHello"
"xxxxxxxFOOyyy"
"yyy"