如何替换ruby中最后一次出现的子串?

Jus*_*ner 30 ruby

我想替换ruby中最后一次出现的子串.什么是最简单的方式?例如,在abc123abc123中,我想将最后一个abc替换为ABC.我怎么能这样做?

Cho*_*ett 36

怎么样

new_str = old_str.reverse.sub(pattern.reverse, replacement.reverse).reverse
Run Code Online (Sandbox Code Playgroud)

例如:

irb(main):001:0> old_str = "abc123abc123"
=> "abc123abc123"
irb(main):002:0> pattern="abc"
=> "abc"
irb(main):003:0> replacement="ABC"
=> "ABC"
irb(main):004:0> new_str = old_str.reverse.sub(pattern.reverse, replacement.reverse).reverse
=> "abc123ABC123"
Run Code Online (Sandbox Code Playgroud)


Mla*_*vić 22

"abc123abc123".gsub(/(.*(abc.*)*)(abc)(.*)/, '\1ABC\4')
#=> "abc123ABC123"
Run Code Online (Sandbox Code Playgroud)

但可能还有更好的方法......

编辑:

......克里斯在下面的评论中提供了.

所以,就像*一个贪婪的运算符,以下就足够了:

"abc123abc123".gsub(/(.*)(abc)(.*)/, '\1ABC\3')
#=> "abc123ABC123"
Run Code Online (Sandbox Code Playgroud)

EDIT2:

还有一个解决方案巧妙地说明了Ruby中的并行数组赋值:

*a, b = "abc123abc123".split('abc', -1)
a.join('abc')+'ABC'+b
#=> "abc123ABC123"
Run Code Online (Sandbox Code Playgroud)

  • 由于贪婪的匹配,只需`str.sub(/(.*)abc /,'\ 1ABC')`就足够了. (14认同)

小智 12

从 Ruby 2.0 开始,我们可以使用\Kwhich 从返回的匹配中删除在它之前匹配的任何文本。结合贪婪的运算符,你会得到这个:

'abc123abc123'.sub(/.*\Kabc/, 'ABC')
#=> "abc123ABC123"
Run Code Online (Sandbox Code Playgroud)

这比 Hirurg103 建议的使用捕获组快大约 1.4 倍,但这种速度是以使用鲜为人知的模式降低可读性为代价的。

更多信息\Khttps : //www.regular-expressions.info/keep.html


Hir*_*103 6

您可以使用String#sub和贪婪正则表达式来实现此目的.*,如下所示:

'abc123abc123'.sub(/(.*)abc/, '\1ABC')
Run Code Online (Sandbox Code Playgroud)


Dan*_*sch 5

这是另一种可能的解决方案:

>> s = "abc123abc123"
=> "abc123abc123"

>> s[s.rindex('abc')...(s.rindex('abc') + 'abc'.length)] = "ABC"
=> "ABC"

>> s
=> "abc123ABC123"
Run Code Online (Sandbox Code Playgroud)


rib*_*mar 5

在大量数据流中搜索时,reverse明确使用会导致性能问题.我用string.rpartition*:

sub_or_pattern = "!"
replacement = "?"
string = "hello!hello!hello"

array_of_pieces = string.rpartition sub_or_pattern
( array_of_pieces[(array_of_pieces.find_index sub_or_pattern)] =  replacement ) rescue nil
p array_of_pieces.join
# "hello!hello?hello"
Run Code Online (Sandbox Code Playgroud)

相同的代码必须使用不出现的字符串sub_or_pattern:

string = "hello_hello_hello"
# ...
# "hello_hello_hello"
Run Code Online (Sandbox Code Playgroud)

*内部rpartition 使用rb_str_subseq().我没有检查该函数是否返回该字符串的副本,但我认为它保留了该字符串部分使用的内存块.reverse使用rb_enc_cr_str_copy_for_substr(),这表明副本一直在进行- 尽管将来String可能会实现一个更智能的类(将标志reversed设置为true,并且在设置时使其所有功能都向后运行),截至目前,效率低下.

而且,Regex模式不能简单地逆转.这个问题只是要求替换子串的最后一次出现,所以,没关系,但是需要更强大的东西的读者不会从最投票的答案中受益(截至本文撰写时)