Руби, удалить последние N символов из строки?


263

Каков предпочтительный способ удаления последних nсимволов из строки?


Если вы знаете суффикс (верхний ответ предполагает, что многие приходят сюда в поисках этого), вы можете использовать delete_suffixRuby 2.5. Больше информации здесь .
SRack

Ответы:


36

Ruby 2.5+

Как рубин 2.5 вы можете использовать delete_suffixили delete_suffix!для достижения этой цели в быстром и читаемом виде.

Документы по методам здесь .

Если вы знаете, что такое суффикс, это идиоматическое (и я бы сказал, даже более читабельное, чем другие ответы здесь):

'abc123'.delete_suffix('123')     # => "abc"
'abc123'.delete_suffix!('123')    # => "abc"

Это даже значительно быстрее (почти 40% с методом взрыва), чем топовый ответ. Вот результат того же теста:

                     user     system      total        real
chomp            0.949823   0.001025   0.950848 (  0.951941)
range            1.874237   0.001472   1.875709 (  1.876820)
delete_suffix    0.721699   0.000945   0.722644 (  0.723410)
delete_suffix!   0.650042   0.000714   0.650756 (  0.651332)

Я надеюсь, что это полезно - обратите внимание, что метод в настоящее время не принимает регулярные выражения, поэтому, если вы не знаете суффикс, он пока не жизнеспособен. Однако, поскольку принятый ответ ( обновление: на момент написания ) требует того же, я подумал, что это может быть полезно для некоторых людей.


1
@JPSilvashy Я никогда не был так рад потерять галочку. Это отличный ответ.
Уэйн Конрад

1
Это отличная и быстрая функция, но это не правильный ответ, потому что она не отвечает на вопрос, который точноWhat is the preferred way of removing the last n characters from a string?
Сэм

1
Спасибо за отзыв @Sam - на этот вопрос был ответ почти девять лет, который работал так же, как этот, с 261 ответом на момент написания статьи. JP принял это и недавно переключился на это, так что я бы сказал, что ответил на их вопрос :) Я думал, что я расскажу об этом как о современной альтернативе и надеюсь, что это поможет людям, которые приземляются здесь. Фактически, я рассмотрел все это в этом вопросе - я надеюсь, что этот метод скоро примет регулярное выражение, хотя есть подходящая альтернатива для вашего случая прямо под этим.
SRack

316
irb> 'now is the time'[0...-4]
=> "now is the "

9
Обратите внимание, что это работает только в Ruby 1.9. В Ruby 1.8 это удалит последние байты , а не последние символы .
Йорг Миттаг

2
Но он, вероятно, имел в виду «байты», если он использует 1.8.x.
DigitalRoss

4
Это работает, но я обнаружил, что abc123.chomp (123) будет в два раза быстрее как для коротких, так и для очень длинных строк. (Ruby 2.0.0-p247) Кто-нибудь может это подтвердить?
Plasmarob

10
Для тех, кто интересуется, почему этот конкретный пример не работает .. есть 3 точки, а не 2, т.е. [0...-4]нет[0..-4]
rorofromfrance

2
@Plamarob Я думаю, что более уместно сказать, что chomp на 53 наносекунды быстрее, чем сказать, что он в два раза быстрее. Тогда вы сможете лучше оценить стоимость и ценность его использования, а также то, можно ли оптимизировать его в данной ситуации.
cesoid

266

Если символы, которые вы хотите удалить, всегда являются одинаковыми символами, подумайте chomp:

'abc123'.chomp('123')    # => "abc"

Преимущества chomp: нет подсчета, и код более четко сообщает, что он делает.

Без аргументов chompудаляет окончание строки DOS или Unix, если оно присутствует:

"abc\n".chomp      # => "abc"
"abc\r\n".chomp    # => "abc"

Из комментариев встал вопрос о скорости использования по #chompсравнению с использованием диапазона. Вот тест, сравнивающий два:

require 'benchmark'

S = 'asdfghjkl'
SL = S.length
T = 10_000
A = 1_000.times.map { |n| "#{n}#{S}" }

GC.disable

Benchmark.bmbm do |x|
  x.report('chomp') { T.times { A.each { |s| s.chomp(S) } } }
  x.report('range') { T.times { A.each { |s| s[0...-SL] } } }
end

Результаты тестов (с использованием CRuby 2.13p242):

Rehearsal -----------------------------------------
chomp   1.540000   0.040000   1.580000 (  1.587908)
range   1.810000   0.200000   2.010000 (  2.011846)
-------------------------------- total: 3.590000sec

            user     system      total        real
chomp   1.550000   0.070000   1.620000 (  1.610362)
range   1.970000   0.170000   2.140000 (  2.146682)

Таким образом, chomp быстрее чем использование диапазона, на ~ 22%.


5
Чоп тоже вариант. Это менее суетливо о том, что удаляется.
Эндрю Гримм

1
Я обнаружил, что на самом деле все наоборот. Реальность такова, что .chomp, похоже, в два раза быстрее.
Plasmarob

3
@Plamarob, тесты в Ruby часто бывают удивительными. Я так часто ошибаюсь, что больше не пытаюсь угадать, что будет быстрее. Кроме того, если ответ будет улучшен результатами теста, не стесняйтесь редактировать его.
Уэйн Конрад

1
Если я правильно читаю код, диапазон занимает около 53 наносекунд дольше, чем chomp. В некоторых ситуациях это может быть значительным тормозом, но, помня об абсолютной скорости (а не только об относительной), можно сказать, следует ли вам пройти через свою кодовую базу и изменить все диапазоны на chomps (где это применимо). Возможно нет.
cesoid

1
Прекрасно работает. И вы можете использовать, chomp!()чтобы действовать на String на месте.
Джошуа Пинтер

57
str = str[0...-n]

5
Обратите внимание, что это работает только в Ruby 1.9. В Ruby 1.8 это удалит последние байты , а не последние символы .
Йорг Миттаг

5
Это лучше, чем выбранный ответ, так как 3 точки (...) легче запомнить, так как -n означает удалить n символов из конца строки.
Лулалала

также "abcd" [0 ..- 2] # => "abc", а "abcd" [0 ...- 2] # => "ab". На мой взгляд, опция диапазона 3 точки приводит к более понятному коду.
mokagio

31

Я бы предложил chop. Я думаю, что это было упомянуто в одном из комментариев, но без ссылок или объяснений, поэтому вот почему я думаю, что это лучше:

Он просто удаляет последний символ из строки, и вам не нужно указывать какие-либо значения, чтобы это произошло.

Если вам нужно убрать более одного персонажа, тогда chompваш лучший выбор. Вот что говорят о рубиновых документахchop :

Возвращает новую строку с последним удаленным символом. Если строка заканчивается на \ r \ n, оба символа удаляются. Применение chop к пустой строке возвращает пустую строку. Строка # chomp часто является более безопасной альтернативой, поскольку она оставляет строку неизменной, если она не заканчивается разделителем записей.

Хотя это в основном используется для удаления разделителей, как \r\nя использовал для удаления последнего символа из простой строки, например, sчтобы сделать слово единственным.


1
Разве это не удалит этот последний символ? Вопрос о «персонажах» во множественном числе
Мэтью

1
Да, вы правы, но chomp ('chars') удалит последние 'chars'. Мне было непонятно, хочет ли ОП конкретные символы или просто N символов.
Какубей

Да, это ответ, только когда вы хотите удалить только одного персонажа (что было со мной, хотя).
Quv

29
name = "my text"
x.times do name.chop! end

Вот в консоли:

>name = "Nabucodonosor"
 => "Nabucodonosor" 
> 7.times do name.chop! end
 => 7 
> name
 => "Nabuco" 

Это эффективно? Кажется, стоит сравнивать результаты с другими ответами :)
SRack

16

Удаление последних nсимволов аналогично сохранению первых length - nсимволов.

Активная поддержка включает в себя String#firstи String#lastметоды, которые обеспечивают удобный способ сохранить или удалить первый / последнийn символы:

require 'active_support/core_ext/string/access'

"foobarbaz".first(3)  # => "foo"
"foobarbaz".first(-3) # => "foobar"
"foobarbaz".last(3)   # => "baz"
"foobarbaz".last(-3)  # => "barbaz"

7

если вы используете рельсы, попробуйте:

"my_string".last(2) # => "ng"

[Изменено]

Чтобы получить строку без последних 2 символов:

n = "my_string".size
"my_string"[0..n-3] # => "my_stri"

Примечание: последняя строка char имеет значение n-1. Итак, для удаления последних 2 мы используем n-3.


2
Это не удаляет последние две буквы. Это возвращает их.
JP Silvashy

1
Вам не нужно сначала измерять строку, ruby ​​изначально использует отрицательные индексы с конца строки
Devon Parsons

3

Вы всегда можете использовать что-то вроде

 "string".sub!(/.{X}$/,'')

куда X количество символов для удаления.

Или с присвоением / использованием результата:

myvar = "string"[0..-X]

где Xколичество символов плюс один для удаления.



1

Если вы в порядке с созданием методов класса и хотите отобрать символы, попробуйте это:

class String
  def chop_multiple(amount)
    amount.times.inject([self, '']){ |(s, r)| [s.chop, r.prepend(s[-1])] }
  end
end

hello, world = "hello world".chop_multiple 5
hello #=> 'hello '
world #=> 'world'


0

Если символы, которые вы хотите удалить, всегда являются одинаковыми, рассмотрите chomp:

'abc123'. chomp ('123')


-3
x = "my_test"
last_char = x.split('').last

3
вопрос был об удалении последних N символов из строки, а не о поиске последнего символа
unnitallman
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.