Ruby 用中间的东西向后看

Ruby 用中间的东西向后看,ruby,regex,Ruby,Regex,我有两种类型的字符串。如果字符串首先包含foo,然后包含bar,则不应触摸该字符串。如果它只包含条,则条,应替换为qux “sometext foo someothetext bar somethirdtext”不应触摸 “sometext bar somethetext”=>“sometext qux somethetext” 看起来我需要使用“反向向后看”,但我无法使其正常工作。目前,我有一个表达: str.gsub! (/(?<!foo)(.*)bar/), '\1qux' s

我有两种类型的字符串。如果字符串首先包含
foo
,然后包含
bar
,则不应触摸该字符串。如果它只包含
,则
,应替换为
qux

  • “sometext foo someothetext bar somethirdtext”
    不应触摸
  • “sometext bar somethetext”
    =>
    “sometext qux somethetext”
看起来我需要使用“反向向后看”,但我无法使其正常工作。目前,我有一个表达:

str.gsub! (/(?<!foo)(.*)bar/), '\1qux'
str.gsub!(/(?

但是,它将两个字符串中的
替换为
qux
。我感觉
*
会把事情搞砸。我无法找到一个查找后面的示例,其中查找后面的组不会立即位于匹配的组之前。

如果可以使用可变长度的查找后面,您可以只替换
的匹配项/(?带有
“qux”

如果不支持可变长度lookbehind,您实际上可以使用lookbehind,因为您不知道开始查找
foo
的位置。以下是使用lookbehind的方法:

str.gsub!  (/\A(((?!foo).)*)bar/m), '\1qux'
说明:

\A           # match at the start of the string
(            # start capture group 1
  (            # start capture group 2, repeat 0 or more times
    (?!foo)      # fail if 'foo' can match here
    .            # match a single character
  )*           # end capture group 2
)            # end capture group 1
bar          # match 'bar'
这将对每个字符执行负前瞻
(?!foo)
,直到我们匹配
bar
,因此它不会匹配
foo
位于
bar
之前的字符串


到字符串开头的锚是必要的,因为如果你可以在字符串的中间开始,在 Foo后,立即开始匹配。多行选项被使用,以便<代码> ./COD>字符将匹配断线,不确定这是否对你所做的是必要的。

你可以这样做:

if str.include? "foo"
  str = str.slice(0, str.index("foo")-1).sub("bar","qux") + str.slice(str.index("foo")-1, str.length)
else
  str = str.sub("bar","qux")
end

它将替换第一个“foo”实例之前的任何“bar”,然后固定字符串的其余部分

也许您可以使用
标志
来跟踪前面是否有
foo

flag = false
"sometext foo someothetext bar somethirdtext"
.gsub(/(foo)|bar/){flag = true if $1; flag ? $& : "qux"}
# => "sometext foo someothetext bar somethirdtext"

flag = false
"sometext bar someothetext"
.gsub(/(foo)|bar/){flag = true if $1; flag ? $& : "qux"}
# => "sometext qux someothetext"