我有两种类型的字符串。如果字符串首先包含foo
bar
bar
,则不应触及该字符串。如果它仅包含bar
,则qux
应替换为"sometext foo someothetext bar somethirdtext"
。
"sometext bar someothetext"
不应该被触及"sometext qux someothetext"
=&gt; str.gsub! (/(?<!foo)(.*)bar/), '\1qux'
看起来我需要使用负面外观,但我无法让它正常工作。目前,我有一个表达:
bar
但是,它会在两个字符串中将qux
替换为.*
。我有一种感觉{{1}}搞砸了。我无法找到背后的示例,其中群组后面的内容不会立即出现在匹配群组之前。
答案 0 :(得分: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
所在的字符串。
到字符串开头的锚是必要的,因为如果你可以从字符串的中间开始,它将在f
foo
之后立即开始匹配。使用多行选项,以便.
字符匹配换行符,不确定这是否对您正在进行的操作是必要的。
答案 1 :(得分: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”,然后在其余的字符串上添加
答案 2 :(得分:0)
也许您可以使用flag
来跟踪前面是否有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"