3

我有两种类型的字符串。如果字符串包含foofirst 和 later bar,则不应触摸它。如果它只包含bar,那么bar,应该替换为qux

  • "sometext foo someothetext bar somethirdtext"不应该被触摸
  • "sometext bar someothetext"=>"sometext qux someothetext"

看起来我需要在后面使用负面的外观,但我无法让它正常工作。目前,我有一个表达:

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

但是,它在两个字符串中都替换bar为 to 。qux我有一种把事情搞砸的感觉.*。我无法找到一个向后看的示例,其中向后看组不会立即在匹配组之前。

4

3 回答 3

0

如果您可以使用可变长度的lookbehinds,您可以将匹配替换/(?<!foo.*)bar/'qux'

如果不支持可变长度的lookbehinds,你真的可以使用lookbehind,因为你不知道开始lookbehind 的位置foo。以下是如何通过前瞻来做到这一点:

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

字符串开头的锚点是必要的,因为如果你可以从字符串的中间开始,它只会在fin之后立即开始匹配foo。使用多行选项以便.字符匹配换行符,不确定这是否对您正在执行的操作是必要的。

于 2013-01-08T20:30:21.897 回答
0

您可以执行以下操作:

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”,然后附加字符串的其余部分

于 2013-01-08T20:38:24.877 回答
0

也许您可以使用 aflag来跟踪是否有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"
于 2013-01-08T22:33:05.293 回答