Ruby, видалити останні шість символів із рядка?


263

Який бажаний спосіб видалення останніх nсимволів з рядка?


Якщо ви знаєте суфікс (головна відповідь говорить про те, що сюди багато шукають), ви можете скористатися delete_suffixз Ruby 2.5. Більше інформації тут .
SRack

Відповіді:


36

Рубін 2,5+

З Ruby 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 це видалить останні байти , а не останні символи .
Йорг W Міттаг

2
Але він, мабуть, мав на увазі "байти", якщо він використовує 1.8.x.
DigitalRoss

4
Це спрацьовує, але я вважаю, що "abc123'.chomp (" 123 ") є вдвічі швидшим як для коротких, так і для дуже довгих рядків. (Ruby 2.0.0-p247) Чи може хтось підтвердити це?
Плазмароб

10
Для тих, хто цікавиться, чому цей конкретний приклад не працює. Є 3 крапки не 2, тобто [0...-4]ні[0..-4]
rorofromfrance

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

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)

Тож чмокання швидше, ніж використання діапазону, на ~ 22%.


5
Чоп - це також варіант. Він менш метушливий щодо того, що видаляється.
Ендрю Грімм

1
Я виявив, що навпаки насправді так. Реальність полягає в тому, що .chomp здається постійно вдвічі швидшим.
Плазмароб

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

1
Якщо я читаю правильно код, діапазон займає приблизно 53 наносекунди довше, ніж chomp. У певних ситуаціях це може бути значним, але враховуючи абсолютну швидкість (а не лише відносну) може сказати вам, чи варто вам пройти свою кодову базу і змінити всі діапазони на чмопи (де це можливо). Напевно, ні.
цезоїд

1
Чудово працює. І ви можете використовувати, chomp!()щоб діяти на String на місці.
Джошуа Пінтер

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

5
Зауважте, що це працює лише в Ruby 1.9. У Ruby 1.8 це видалить останні байти , а не останні символи .
Йорг W Міттаг

5
Це краще, ніж обрана відповідь, оскільки 3 крапки (...) простіше запам'ятовувати, оскільки -n означає вивести n символів з кінця рядка.
lulalala

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

31

Я б запропонував chop . Я думаю, що це було зазначено в одному з коментарів, але без посилань чи пояснень, тому ось чому я вважаю, що це краще:

Він просто видаляє останній символ із рядка, і вам не потрібно вказувати жодних значень, щоб це відбулося.

Якщо вам потрібно видалити більше одного символу, то chompце найкраща ставка. Про це мають сказати рубінові документиchop :

Повертає нову рядок із останнім видаленим символом. Якщо рядок закінчується \ r \ n, обидва символи видаляються. Застосування chop до порожнього рядка повертає порожній рядок. Рядок # chomp часто є більш безпечною альтернативою, оскільки він залишає рядок незмінним, якщо він не закінчується роздільником записів.

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


1
Хіба це не просто видалить цей єдиний останній символ? Питання про "персонажів" у множині
maetthew

1
Так, ви маєте рацію, але chomp ("chars") видалить останні "символи". Мені було не ясно, чи бажає ОП конкретних символів чи просто N символів.
kakubei

Так, це відповідь, лише тоді, коли ви хочете видалити лише одного символу (що, мабуть, було і в мене).
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"

Примітка: останній рядковий рядок знаходиться на n-1. Отже, для видалення останніх 2 використовуємо n-3.


2
Останні дві літери не видаляються. Це повертає їх.
JP Silvashy

1
Вам не потрібно спочатку вимірювати рядок, рубін використовує негативні індекси з кінця рядка
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

Використання регулярного вираження:

str = 'string'
n = 2  #to remove last n characters

str[/\A.{#{str.size-n}}/] #=> "stri"

0

Якщо символи, які ви хочете видалити, завжди є одними і тими ж символами, то врахуйте chomp:

'abc123'. шипшина ('123')


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.