I want to replace the last occurrence of a substring in Ruby. What's the easiest way? For example, in abc123abc123, I want to replace the last abc to ABC. How do I do that?
相关问题
- How to specify memcache server to Rack::Session::M
- Why am I getting a “C compiler cannot create execu
- reference to a method?
- ruby 1.9 wrong file encoding on windows
- gem cleanup shows error: Unable to uninstall bundl
相关文章
- Ruby using wrong version of openssl
- Difference between Thread#run and Thread#wakeup?
- how to call a active record named scope with a str
- “No explicit conversion of Symbol into String” for
- Segmentation fault with ruby 2.0.0p247 leading to
- How to detect if an element exists in Watir
- uninitialized constant Mysql2::Client::SECURE_CONN
- ruby - simplify string multiply concatenation
Since Ruby 2.0 we can use
\K
which removes any text matched before it from the returned match. Combine with a greedy operator and you get this:This is about 1.4 times faster than using capturing groups as Hirurg103 suggested, but that speed comes at the cost of lowering readability by using a lesser-known pattern.
more info on
\K
: https://www.regular-expressions.info/keep.htmlWhen searching in huge streams of data, using
reverse
will definitively* lead to performance issues. I usestring.rpartition
*:The same code must work with a string with no occurrences of
sub_or_pattern
:*
rpartition
usesrb_str_subseq()
internally. I didn't check if that function returns a copy of the string, but I think it preserves the chunk of memory used by that part of the string.reverse
usesrb_enc_cr_str_copy_for_substr()
, which suggests that copies are done all the time -- although maybe in the future a smarterString
class may be implemented (having a flagreversed
set to true, and having all of its functions operating backwards when that is set), as of now, it is inefficient.Moreover,
Regex
patterns can't be simply reversed. The question only asks for replacing the last occurrence of a sub-string, so, that's OK, but readers in the need of something more robust won't benefit from the most voted answer (as of this writing)But probably there is a better way...
Edit:
...which Chris kindly provided in the comment below.
So, as
*
is a greedy operator, the following is enough:Edit2:
There is also a solution which neatly illustrates parallel array assignment in Ruby:
simple and efficient:
I've used this handy helper method quite a bit:
If you want to make it more Rails-y, extend it on the String class itself:
Then you can just call it directly on any String instance, eg
"fooBAR123BAR".gsub_last("BAR", "FOO") == "fooBAR123FOO"
Here's another possible solution: