Как заменить последнее вхождение подстроки в ruby? - PullRequest
28 голосов
/ 06 июля 2010

Я хочу заменить последнее вхождение подстроки в ruby. Какой самый простой способ? Например, в abc123abc123 я хочу заменить последний abc на ABC . Как я могу это сделать?

Ответы [ 9 ]

35 голосов
/ 06 июля 2010

Как насчет

new_str = old_str.reverse.sub(pattern.reverse, replacement.reverse).reverse

Например:

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"
21 голосов
/ 06 июля 2010
"abc123abc123".gsub(/(.*(abc.*)*)(abc)(.*)/, '\1ABC\4')
#=> "abc123ABC123"

Но, возможно, есть лучший способ ...

Редактировать:

... который Крис любезно предоставил в комментарии ниже.

Итак,поскольку * является жадным оператором, достаточно следующего:

"abc123abc123".gsub(/(.*)(abc)(.*)/, '\1ABC\3')
#=> "abc123ABC123"

Edit2:

Существует также решение, которое аккуратно иллюстрирует параллельное присвоение массива в Ruby:

*a, b = "abc123abc123".split('abc', -1)
a.join('abc')+'ABC'+b
#=> "abc123ABC123"
5 голосов
/ 28 декабря 2016

При поиске в огромных потоках данных использование 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"

Тот же код должен работать со строкой без вхождений sub_or_pattern:

string = "hello_hello_hello"
# ...
# "hello_hello_hello"

*rpartition использует rb_str_subseq() внутренне,Я не проверял, возвращает ли эта функция копию строки, но я думаю, что она сохраняет часть памяти, используемую этой частью строки.reverse использует rb_enc_cr_str_copy_for_substr(), что предполагает, что копии выполняются постоянно - хотя, возможно, в будущем может быть реализован более умный класс String (с флагом reversed, установленным в значение true, и имеющим все его функцииработая в обратном направлении, когда это установлено), на данный момент, это неэффективно.

Более того, шаблоны Regex нельзя просто поменять местами.Вопрос требует только замены последнего вхождения подстроки, так что все в порядке, но читатели, нуждающиеся в чем-то более надежном, не получат пользу от ответа с наибольшим количеством голосов (на момент написания статьи)

5 голосов
/ 16 января 2011

Вот еще одно возможное решение:

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

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

>> s
=> "abc123ABC123"
2 голосов
/ 21 ноября 2017

Этого можно добиться с помощью gsub и жадного регулярного выражения .*, например:

'abc123abc123'.gsub(/(.*)abc/, '\1ABC')
2 голосов
/ 29 августа 2013

просто и эффективно:

s = "abc123abc123abc"
p = "123"
s.slice!(s.rindex(p), p.size)
s == "abc123abcabc"
1 голос
/ 31 августа 2017

Я довольно часто использовал этот удобный вспомогательный метод:

def gsub_last(str, source, target)
  return str unless str.include?(source)
  top, middle, bottom = str.rpartition(source)
  "#{top}#{target}#{bottom}"
end

Если вы хотите сделать его более Rails-y, расширьте его на сам класс String:

class String
  def gsub_last(source, target)
    return self unless self.include?(source)
    top, middle, bottom = self.rpartition(source)
    "#{top}#{target}#{bottom}"
  end
end

Тогда вы можете просто вызвать его напрямую в любом экземпляре String, например, "fooBAR123BAR".gsub_last("BAR", "FOO") == "fooBAR123FOO"

1 голос
/ 06 июля 2010
string = "abc123abc123"
pattern = /abc/
replacement = "ABC"

matches = string.scan(pattern).length
index = 0
string.gsub(pattern) do |match|
  index += 1
  index == matches ? replacement : match
end
#=> abc123ABC123
0 голосов
/ 03 мая 2018
.gsub /abc(?=[^abc]*$)/, 'ABC'

Соответствует «abc», а затем подтверждает ((? =) Положительный прогноз), что никакие другие символы до конца строки не являются «abc».

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...