Ruby, dizeden son N karakteri sil?


263

nBir dizeden son karakterleri kaldırmanın tercih edilen yolu nedir ?


Eğer son eki biliyorsanız (en iyi cevap buraya çok şey gelip gelmediğini gösterir), delete_suffixRuby 2.5'ten kullanabilirsiniz . Daha fazla bilgi burada .
19'da SRack

Yanıtlar:


36

Yakut 2.5+

Ruby 2.5'den itibaren bunu hızlı ve okunabilir bir şekilde elde etmek için delete_suffixveya kullanabilirsiniz delete_suffix!.

Yöntemlerle ilgili dokümanlar burada .

Son ekin ne olduğunu biliyorsanız, bu deyimseldir (ve buradaki diğer cevaplardan daha da okunabilir olduğunu iddia ediyorum):

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

Üst yanıttan daha hızlıdır ( patlama yöntemiyle neredeyse % 40 ). İşte aynı karşılaştırmanın sonucu:

                     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)

Umarım bu yararlıdır - yöntemin şu anda normal ifadeyi kabul etmediğini unutmayın, bu nedenle soneki bilmiyorsanız şimdilik geçerli değildir. Ancak, kabul edilen cevap ( güncelleme: yazma sırasında ) aynı şekilde belirttiğinden, bunun bazı insanlar için yararlı olabileceğini düşündüm.


1
@JPSilvashy Onay işaretini kaybetmekten hiç memnun kalmadım. Bu harika bir cevap.
Wayne Conrad

1
Bu harika ve hızlı bir işlev, ama bu doğru cevap değil çünkü tam olarak soruyu cevaplamıyorWhat is the preferred way of removing the last n characters from a string?
Sam

1
@Sam geri bildirimi için teşekkür ederiz - bu sorunun neredeyse dokuz yıl boyunca aynı şekilde çalışan bir cevabı vardı, yazma sırasında 261 upvotes ile. JP kabul ve bunu cevap söyleyebilirim bu yüzden son zamanlarda, bu geçiş onların ben modern bir alternatif olarak bu pop düşündüm soruyu :) ve burada karaya insanlara yardımcı olur. Aslında, tüm bunları soruda ele aldım - umarım bu yöntemin yakında bir normal ifadeyi kabul etmesine rağmen, durumunuzun hemen altında bunun için mükemmel bir alternatif var.
SRack

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

9
Bunun yalnızca Ruby 1.9'da çalıştığını unutmayın. Ruby 1.8'de bu , son karakterleri değil son baytları kaldıracaktır .
Jörg W Mittag

2
Ancak 1.8.x kullanıyorsa muhtemelen "bayt" anlamına geliyordu.
DigitalRoss

4
Bu işe yarıyor, ama 'abc123'.chomp (' 123 ') kısa ve çok uzun dizeleri için iki kat daha hızlı buluyorum. (Ruby 2.0.0-p247) Bunu onaylayan var mı?
Plasmarob

10
Bu özel örneğin neden çalışmadığını merak edenler için ... 2 değil 3 nokta var[0...-4][0..-4]
rorofromfrance

2
@Plamarob Bence chomp'un 53 nanosaniye daha hızlı olduğunu söylemek iki kat daha hızlı olduğunu söylemek daha uygun. Daha sonra, maliyeti kullanmanın maliyetine karşı değerini ve belirli bir durumda optimize etmenin bir şey olup olmayacağını daha iyi tahmin edebilirsiniz.
cesoid

266

Kaldırmak istediğiniz karakterler her zaman aynı karakterlerse, chompşunları göz önünde bulundurun :

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

Avantajları chomp: sayma yok ve kod ne yaptığını daha net bir şekilde iletiyor.

chompBağımsız değişken olmadan , varsa DOS veya Unix satır sonunu kaldırır:

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

Yorumlardan, #chompbir aralığı kullanma yerine kullanım hızı konusunda bir soru vardı . İşte ikisini karşılaştıran bir kıyaslama:

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

Deney Sonuçları (CRuby 2.13p242 kullanarak):

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)

Bu nedenle chomp, ~% 22 bir aralık kullanmaktan daha hızlıdır.


5
Pirzola da bir seçenektir. Neyin kaldırıldığı hakkında daha az telaşlı.
Andrew Grimm

1
Bunun tam tersi olduğunu doğru buldum. Gerçek şu ki .chomp sürekli olarak iki kat daha hızlı görünüyor.
Plasmarob

3
@Plamarob, Ruby'deki testler genellikle şaşırtıcı. O kadar sık ​​yanılıyorum ki artık neyin daha hızlı olacağını tahmin etmeye çalışmıyorum. Ayrıca, cevap karşılaştırma sonuçlarıyla daha iyi hale getirilecekse, lütfen düzenlemekten çekinmeyin.
Wayne Conrad

1
Kodu doğru okuyorsam, aralık chomp'tan yaklaşık 53 nanosaniye daha uzun sürer. Belirli durumlarda önemli bir sürükleme olabilir, ancak mutlak hızı akılda tutmak (sadece akrabadan ziyade), kod tabanınızdan geçmeniz ve tüm aralıklarınızı chomps (uygun olan yerlerde) değiştirip değiştirmemeniz gerektiğini söyleyebilir. Muhtemelen değil.
cesoid

1
Harika çalışıyor. Ve chomp!()yerinde Dize üzerinde hareket etmek için kullanabilirsiniz .
Joshua Pinter

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

5
Bunun yalnızca Ruby 1.9'da çalıştığını unutmayın. Ruby 1.8'de bu , son karakterleri değil son baytları kaldıracaktır .
Jörg W Mittag

5
Bu seçilen yanıttan daha iyidir, çünkü 3 nokta (...) ezberlenmesi daha kolaydır, çünkü -n, dizenin sonundan n karakter çıkarmak anlamına gelir.
lulalala

ayrıca "abcd" [0 ..- 2] # => "abc", "abcd" [0 ...- 2] # => "ab". Bence 3 nokta aralığı seçeneği daha açıklayıcı bir kodla sonuçlanır.
mokagio

31

Ben öneririm chop. Ben yorumlardan birinde bahsedildi ama bağlantılar veya açıklamalar olmadan düşünüyorum bu yüzden neden daha iyi olduğunu düşünüyorum:

Bir dizeden son karakteri siler ve bunun gerçekleşmesi için herhangi bir değer belirtmeniz gerekmez.

Birden fazla karakteri kaldırmanız gerekiyorsa chomp, en iyi bahistir. Bu nedir yakut dokümanlar hakkında söylemek zorunda chop:

Son karakter kaldırılmış olarak yeni bir Dize döndürür. Dize \ r \ n ile biterse, her iki karakter de kaldırılır. Boş bir dizeye chop uygulamak boş bir dize döndürür. Dize # chomp genellikle daha güvenli bir alternatiftir, çünkü kayıt ayırıcıyla bitmezse dizgiyi değiştirmeden bırakır.

Her ne kadar çoğunlukla \r\nbasit bir dizeden son karakteri kaldırmak için kullandığım gibi ayırıcıları kaldırmak için kullanılır, örneğin skelimeyi tekil yapmak için.


1
Bu sadece o son karakteri kaldırmaz mı? Soru çoğul "karakterler" hakkında
maetthew

1
Evet haklısınız, ancak chomp ('chars') son 'chars'ları kaldıracak. OP'nin belirli karakterler mi yoksa sadece N karakterler mi istediği net değildi.
kakubei

Evet, bu cevap, sadece tek bir karakteri kaldırmak istediğinizde (bu benim için de geçerliydi).
Quv

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

Konsolda:

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

Bu verimli mi? Diğer cevaplara göre bir kıyaslama değerinde gibi görünüyor :)
SRack

16

Son nkarakterleri bırakmak ilk length - nkarakterleri tutmakla aynıdır .

Aktif Destek , ilk / son karakterleri saklamak veya bırakmak için uygun bir yol sağlayan yöntemler String#firstve String#lastyöntemler içerir 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

ray kullanıyorsanız, şunu deneyin:

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

[REDAKTE]

Son 2 karakter OLMADAN dizeyi almak için:

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

Not: Son karakter dizisi n-1'de. Yani, son 2'yi kaldırmak için n-3 kullanıyoruz.


2
Bu son iki harfi kaldırmaz. Onları döndürür.
JP Silvashy

1
İlk önce ipi ölçmenize gerek yok, ruby ​​yerel olarak ipin sonundan negatif indeksler kullanıyor
Devon Parsons

3

Her zaman böyle bir şey kullanabilirsiniz

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

Kaldırılacak Xkarakter sayısı nerede .

Veya sonucu atayarak / kullanarak:

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

nerede Xkarakter sayısıdır artı bir kaldırın.



1

Sınıf yöntemleri oluşturma konusunda sorun yaşıyorsanız ve doğradığınız karakterleri istiyorsanız, şunu deneyin:

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

Normal ifade kullanarak:

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

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

0

Kaldırmak istediğiniz karakterler her zaman aynı karakterlerse, chomp düşünün:

'abc123'. pirzola ('123')


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

3
soru, bir karakterdeki son N karakteri kaldırmakla ilgiliydi, son karakteri bulmakla ilgili değil
unnitallman
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.