[英]How to find last occurrence of a substring in a given string?
我有一个字符串,它描述了一些单词,如果结尾 == “jk”,我必须将它的结尾更改为“sd”。 例如,我有一个词:“lazer jk ”,我需要从中获取“lazer sd ”。
我尝试使用 method.gsub,。 但是如果我们在一个单词中多次出现子字符串“jk”,它就不能正常工作。
String#rindex
返回给定子字符串最后一次出现的索引
String#[]=
可以接受两个整数参数,第一个是开始替换的索引,第二个是被替换字符串的长度
您可以这样使用它们:
replaced = "foo"
replacing = "booo"
string = "foo bar foo baz"
string[string.rindex(replaced), replaced.size] = replacing
string
# => "foo bar booo baz"
"jughjkjkjk\njk".sub(/jk$\z/, 'sd')
=> "jughjkjkjk\nsd"
没有 $ 可能就足够了。
听起来您只想替换特定的后缀。 如果是这样,我可能会建议将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 修改了字符串的长度时,才会添加新的后缀。 否则,字符串保持不变。
如果目标是替换 LAST OCCURRENCE(而不是仅后缀),那么这可以通过使用sub
和reverse
来完成:
string = "jklazerjkm"
old_substring = "jk"
new_substring = "sd"
string.reverse.sub(old_substring.reverse, new_substring.reverse).reverse
#=> "jklazersdm"
用其他内容替换字符串末尾的"jk"
很简单,无需担心字符串中可能存在的"jk"
的其他实例即可解决,因此我认为这不是要求的内容。 相反,我假设问题是用"sd"
替换字符串中"jk"
的最后一个实例。
下面是两个将String#sub与正则表达式结合使用的解决方案。
使用否定的前瞻
这里的想法是匹配"jk"
,前提是它后面没有跟在字符串中的另一个实例"jk"
。
"lajkz\nejkrjklm".sub(/jk(?!.*jk)/m, "sd")
#=> "lajkz\nejkrsdlm"
捕获字符串中最后一个"jk"
之前的部分
匹配项(如果有的话)由字符串的前面和最后一个 "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.
请注意,在这两个表达式中.*
都是贪心的,这意味着它会匹配尽可能多的字符,包括"jk"
,只要满足表达式的其他要求,此处匹配字符串中"jk"
的最后一个实例.
这是一个不同的解决方案:
str = "jughjkjkjk\njk"
pattern = "jk"
replace_with = "sd"
str = str.reverse.sub(pattern.reverse, replace_with.reverse).reverse
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.