ruby-on-rails 如何在给定的字符串中找到子字符串的最后一次出现?

pvabu6sv  于 2022-12-20  发布在  Ruby
关注(0)|答案(6)|浏览(156)

我有一个字符串,它描述了一些单词,我必须改变它的结尾为“sd”,如果结束==“jk”.例如,我有一个单词:“雷蛇jk",我需要从它得到“雷蛇sd"。
我试着使用方法.gsub!,但是如果我们在一个单词中有不止一个子字符串“jk”,它就不能正常工作。

goqiplq2

goqiplq21#

String#rindex返回给定子字符串最后一次出现的索引
String#[]=可以接受两个整数参数,第一个是开始替换的索引,第二个是被替换字符串的长度
您可以按以下方式使用它们:

replaced = "foo"
replacing = "booo"

string = "foo bar foo baz"
string[string.rindex(replaced), replaced.size] = replacing

string
# => "foo bar booo baz"
uurv41yg

uurv41yg2#

"jughjkjkjk\njk".sub(/jk$\z/, 'sd')
 => "jughjkjkjk\nsd"

没有美元可能就足够了。

a1o7rhls

a1o7rhls3#

听起来你只想替换一个特定的后缀,如果是这样,我可能会建议使用sub沿着一个锚定正则表达式(只在字符串末尾检查所需的字符):

string_1 = "lazerjk"
string_2 = "lazerjk\njk"
string_3 = "lazerjkr"

string_1.sub(/jk\z/, "sd")  
#=>  "lazersd"

string_2.sub(/jk\z/, "sd")  
#=>  "lazerjk\nsd"

string_3.sub(/jk\z/, "sd")
#=>  "lazerjkr"

或者,您可以完全不使用正则表达式,使用reverse!方法沿着一个简单的条件语句(仅当后缀存在时)来执行sub!

string = "lazerjk"
old_suffix = "jk"
new_suffix = "sd"
string.reverse!.sub!(old_suffix.reverse, new_suffix.reverse).reverse! if string.end_with? (old_suffix)
string 
#=>  "lazersd"

或者,您甚至可以使用一种完全不同的方法。下面是一个示例,使用chomp删除不需要的后缀,然后使用ljust为修改后的字符串填充所需的后缀。

string = "lazerjk"
string.chomp("jk").ljust(string.length, "sd")
#=>  "lazersd"

注意,只有当字符串的长度被初始chomp修改时,才会添加新的后缀,否则,字符串保持不变。

e4eetjau

e4eetjau4#

如果目标是替换LAST OCCURRENCE(与仅后缀相反),则可以通过将subreverse沿着使用来实现:

string = "jklazerjkm"
old_substring = "jk"
new_substring = "sd"
string.reverse.sub(old_substring.reverse, new_substring.reverse).reverse
#=>  "jklazersdm"
ggazkfy8

ggazkfy85#

在字符串的末尾用其他东西替换"jk"是很简单的,可以不用考虑字符串中可能存在的"jk"的其他示例,所以我假设这不是要问的问题,而是假设用"sd"替换字符串中"jk"的最后一个示例。
下面是两个将String#sub与正则表达式结合使用的解决方案。

使用负前瞻

这里的想法是匹配"jk",前提是在字符串后面没有"jk"的另一个示例。

"lajkz\nejkrjklm".sub(/jk(?!.*jk)/m, "sd")
  #=> "lajkz\nejkrsdlm"

捕获字符串中最后一个"jk"之前的部分

匹配项(如果存在)由字符串的前面加上最后一个"jk"组成,后者将替换为捕获的字符串加上"sd"

"lajkz\nejkrjklm".sub(/\A(.*)jk/m) { $1 + "sd" }
  #=> "lajkz\nejkrsdlm"

这两个正则表达式可以用 * 自由空格模式 * 来编写,以使它们自文档化。

/
jk    # match literal
(?!   # begin a negative lookahead
  .*  # match zero or more characters other than line terminators
  jk  # match literal
)     # end negative lookahead
/mx   # invoke multiline and free-spacing regex definition modes.

多行模式使.匹配任何字符,包括行结束符。
第二个正则表达式可以写为如下。

\A    # match the beginning of the string
(.*)  # match zero or more characters other than line terminators
      # and save the match to capture group 1
jk    # match literal
/mx   # invoke multiline and free-spacing regex definition modes.

注意,在两个表达式中,.*都是 greedy,这意味着只要满足表达式的其他要求,它将匹配尽可能多的字符,包括"jk",这里匹配字符串中"jk"的最后一个示例。

pnwntuvh

pnwntuvh6#

下面是一个不同的解决方案:

str = "jughjkjkjk\njk"
pattern = "jk"
replace_with = "sd"
str = str.reverse.sub(pattern.reverse, replace_with.reverse).reverse

相关问题