Ruby, hapus N karakter terakhir dari sebuah string?

263

Apa cara yang disukai untuk menghapus nkarakter terakhir dari string?

JP Silvashy
sumber
Jika Anda tahu sufiks (jawaban teratas menyarankan banyak yang datang ke sini mencari ini), Anda dapat menggunakan delete_suffixdari Ruby 2.5. Info lebih lanjut di sini .
SRack

Jawaban:

36

Ruby 2.5+

Pada Ruby 2.5 Anda dapat menggunakan delete_suffixatau delete_suffix!untuk mencapainya dengan cara yang cepat dan mudah dibaca.

Dokumen tentang metode ada di sini .

Jika Anda tahu apa sufiks itu, ini idiom (dan saya berpendapat, bahkan lebih mudah dibaca daripada jawaban lain di sini):

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

Ini bahkan jauh lebih cepat (hampir 40% dengan metode bang) daripada jawaban teratas. Inilah hasil dari tolok ukur yang sama:

                     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)

Saya harap ini berguna - perhatikan metode saat ini tidak menerima regex jadi jika Anda tidak tahu akhiran itu tidak layak untuk saat ini. Namun, ketika jawaban yang diterima ( pembaruan: pada saat penulisan ) menentukan hal yang sama, saya pikir ini mungkin berguna bagi beberapa orang.

SRack
sumber
1
@ JPSilvashy Saya tidak pernah lebih senang kehilangan tanda centang. Ini jawaban yang bagus.
Wayne Conrad
1
Ini adalah fungsi yang hebat dan cepat, tetapi ini bukan jawaban yang tepat karena tidak menjawab pertanyaan yang sebenarnyaWhat is the preferred way of removing the last n characters from a string?
Sam
1
Terima kasih atas umpan baliknya @Sam - pertanyaan ini memiliki jawaban selama hampir sembilan tahun yang bekerja sama dengan yang ini, dengan 261 suara positif pada saat penulisan. JP menerimanya dan baru-baru ini beralih ke ini, jadi saya akan mengatakan itu menjawab pertanyaan mereka :) Saya pikir saya akan memasukkan ini sebagai alternatif modern, dan berharap itu membantu orang-orang yang mendarat di sini. Sebenarnya, saya sudah membahas semua ini dalam pertanyaan - Saya berharap metode ini segera menerima regex, meskipun ada alternatif yang sempurna untuk kasus Anda tepat di bawah ini.
SRack
316
irb> 'now is the time'[0...-4]
=> "now is the "
DigitalRoss
sumber
9
Perhatikan bahwa ini hanya berfungsi di Ruby 1.9. Di Ruby 1.8, ini akan menghapus byte terakhir , bukan karakter terakhir .
Jörg W Mittag
2
Tapi dia mungkin berarti "byte" jika dia menggunakan 1.8.x.
DigitalRoss
4
Ini berhasil, tetapi saya menemukan 'abc123'.chomp (' 123 ') dua kali lebih cepat untuk string pendek dan sangat panjang. (Ruby 2.0.0-p247) Adakah yang bisa mengkonfirmasi ini?
Plasmarob
10
Bagi mereka yang bertanya-tanya mengapa contoh khusus ini tidak bekerja .. ada 3 titik bukan 2 yaitu [0...-4]tidak[0..-4]
rorofromfrance
2
@ Plamarob Saya pikir itu lebih relevan untuk mengatakan bahwa chomp adalah 53 nanodetik lebih cepat daripada mengatakan bahwa chomp adalah dua kali lebih cepat. Maka Anda dapat memperkirakan biaya vs nilai penggunaannya dengan lebih baik, dan apakah hal itu akan menjadi hal yang optimal dalam situasi tertentu.
cesoid
266

Jika karakter yang ingin Anda hapus selalu karakter yang sama, maka pertimbangkan chomp:

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

Keuntungannya chompadalah: tidak menghitung, dan kode lebih jelas mengkomunikasikan apa yang dilakukannya.

Tanpa argumen, chomphapus akhir baris DOS atau Unix, jika ada:

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

Dari komentar, ada pertanyaan tentang kecepatan penggunaan #chompversus penggunaan rentang. Berikut ini adalah perbandingan yang membandingkan keduanya:

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

Hasil Benchmark (menggunakan 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)

Jadi chomp lebih cepat daripada menggunakan rentang, ~ 22%.

Wayne Conrad
sumber
5
Chop juga merupakan opsi. Ini kurang rewel tentang apa yang dihapus.
Andrew Grimm
1
Saya menemukan yang sebaliknya sebenarnya benar. Kenyataannya adalah .chomp tampaknya konsisten dua kali lebih cepat.
Plasmarob
3
@ Plamarob, Tingkatan yang dicapai di Ruby seringkali mengejutkan. Saya sering salah sehingga saya tidak lagi mencoba menebak apa yang akan lebih cepat. Juga, jika jawabannya akan ditingkatkan oleh hasil benchmark, silakan mengeditnya.
Wayne Conrad
1
Jika saya membaca kode dengan benar, rentang membutuhkan waktu sekitar 53 nanodetik lebih lama dari chomp. Ini mungkin merupakan hambatan yang signifikan dalam situasi tertentu, tetapi menjaga kecepatan absolut dalam pikiran (bukan hanya relatif) dapat memberi tahu Anda apakah Anda harus melalui basis kode dan mengubah semua rentang Anda menjadi chomps (jika berlaku). Mungkin tidak.
cesoid
1
Bagus sekali. Dan Anda dapat menggunakan chomp!()untuk bertindak pada String di tempat.
Joshua Pinter
57
str = str[0...-n]
Nakilon
sumber
5
Perhatikan bahwa ini hanya berfungsi di Ruby 1.9. Di Ruby 1.8, ini akan menghapus byte terakhir , bukan karakter terakhir .
Jörg W Mittag
5
Ini lebih baik daripada jawaban yang dipilih, karena 3 titik (...) lebih mudah diingat karena -n berarti mengeluarkan n karakter dari ujung string.
lulalala
juga "abcd" [0 ..- 2] # => "abc" sementara "abcd" [0 ...- 2] # => "ab". Menurut pendapat saya, opsi rentang 3 titik menghasilkan kode yang lebih jelas.
mokagio
31

Saya akan menyarankan chop. Saya pikir itu telah disebutkan dalam salah satu komentar tetapi tanpa tautan atau penjelasan, jadi inilah mengapa saya pikir itu lebih baik:

Itu hanya menghapus karakter terakhir dari string dan Anda tidak perlu menentukan nilai apa pun untuk itu terjadi.

Jika Anda perlu menghapus lebih dari satu karakter maka chompitu taruhan terbaik Anda. Inilah yang dikatakan dokter rubi tentang chop:

Mengembalikan String baru dengan karakter terakhir dihapus. Jika string diakhiri dengan \ r \ n, kedua karakter akan dihapus. Menerapkan pemotongan ke string kosong akan mengembalikan string kosong. String # chomp seringkali merupakan alternatif yang lebih aman, karena string tidak akan berubah jika tidak diakhiri dengan pemisah rekaman.

Meskipun ini sebagian besar digunakan untuk menghapus pemisah seperti \r\nsaya telah menggunakannya untuk menghapus karakter terakhir dari string sederhana, misalnya suntuk membuat kata singular.

kakubei
sumber
1
Bukankah itu hanya menghapus satu karakter terakhir? Pertanyaannya adalah tentang "karakter" dalam bentuk jamak
maetthew
1
Ya, Anda benar, tetapi chomp ('chars') akan menghapus 'chars' terakhir. Tidak jelas bagi saya apakah OP menginginkan karakter tertentu atau hanya karakter N.
kakubei
Ya, ini jawabannya, hanya ketika Anda ingin menghapus hanya satu karakter (yang merupakan kasus dengan saya).
Quv
29
name = "my text"
x.times do name.chop! end

Di sini, di konsol:

>name = "Nabucodonosor"
 => "Nabucodonosor" 
> 7.times do name.chop! end
 => 7 
> name
 => "Nabuco" 
joscas
sumber
Apakah ini efisien? Tampaknya satu perbandingan perbandingan layak untuk jawaban lain :)
SRack
16

Menjatuhkan nkarakter terakhir sama dengan menjaga length - nkarakter pertama .

Dukungan Aktif termasuk String#firstdan String#lastmetode yang memberikan cara mudah untuk menjaga atau menjatuhkan karakter pertama / terakhir n:

require 'active_support/core_ext/string/access'

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

jika Anda menggunakan rel, coba:

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

[Diedit]

Untuk mendapatkan string TANPA 2 karakter terakhir:

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

Catatan: char string terakhir ada di n-1. Jadi, untuk menghapus 2 terakhir, kami menggunakan n-3.

Guihen
sumber
2
Ini tidak menghapus dua huruf terakhir. Itu mengembalikan mereka.
JP Silvashy
1
Anda tidak perlu mengukur dawai terlebih dahulu, ruby ​​menggunakan indeks negatif dari akhir dawai secara asli
Devon Parsons
3

Anda selalu dapat menggunakan sesuatu seperti

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

Di mana Xjumlah karakter yang akan dihapus.

Atau dengan menugaskan / menggunakan hasilnya:

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

di mana Xjumlah karakter ditambah satu untuk dihapus.

Zsolt Botykai
sumber
1

Jika Anda tidak masalah dengan membuat metode kelas dan ingin karakter yang Anda potong, coba ini:

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'
Ben Aubin
sumber
0

Menggunakan regex:

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

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

Jika karakter yang ingin Anda hapus selalu karakter yang sama, maka pertimbangkan chomp:

'abc123'. chomp ('123')

Poonkodi
sumber
-3
x = "my_test"
last_char = x.split('').last
Reshmi Mitra
sumber
3
pertanyaan adalah tentang menghapus karakter N terakhir dari sebuah string, bukan tentang menemukan karakter terakhir
unitallall