Ruby, rimuovi gli ultimi N caratteri da una stringa?


263

Qual è il modo preferito di rimuovere gli ultimi ncaratteri da una stringa?


Se conosci il suffisso (la risposta in alto suggerisce molto vieni qui a cercarlo), puoi usare delete_suffixda Ruby 2.5. Maggiori informazioni qui .
SRack,

Risposte:


36

Rubino 2.5+

A partire da Ruby 2.5 è possibile utilizzare delete_suffixo delete_suffix!per raggiungere questo obiettivo in modo rapido e leggibile.

I documenti sui metodi sono qui .

Se sai qual è il suffisso, questo è idiomatico (e direi, ancora più leggibile rispetto alle altre risposte qui):

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

È anche significativamente più veloce (quasi il 40% con il metodo del botto) rispetto alla risposta migliore. Ecco il risultato dello stesso benchmark:

                     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)

Spero che sia utile - nota che il metodo attualmente non accetta una regex, quindi se non conosci il suffisso non è praticabile per il momento. Tuttavia, poiché la risposta accettata ( aggiornamento: al momento della stesura ) impone lo stesso, ho pensato che ciò potesse essere utile ad alcune persone.


1
@JPSilvashy Non sono mai stato più contento di perdere un segno di spunta. Questa è un'ottima risposta
Wayne Conrad,

1
Questa è una funzione grande e veloce, ma questa non è la risposta giusta perché non risponde alla domanda che è esattamenteWhat is the preferred way of removing the last n characters from a string?
Sam

1
Grazie per il feedback @Sam - questa domanda ha avuto una risposta per quasi nove anni che ha funzionato allo stesso modo di questa, con 261 voti al momento della stesura. JP l'ha accettato e recentemente è passato a questo, quindi direi che ha risposto alla sua domanda :) Ho pensato di inserire questo come un'alternativa moderna e spero che aiuti le persone che arrivano qui. In effetti, ho trattato tutto questo nella domanda: spero che questo metodo accetti presto una regex, anche se c'è un'alternativa perfetta per il tuo caso proprio sotto questo.
SRack

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

9
Si noti che questo funziona solo in Ruby 1.9. In Ruby 1.8, questo rimuoverà gli ultimi byte , non gli ultimi caratteri .
Jörg W Mittag,

2
Ma probabilmente intendeva "byte" se sta usando 1.8.x.
DigitalRoss,

4
Questo funziona, ma sto scoprendo che 'abc123'.chomp (' 123 ') è due volte più veloce sia per le corde corte che per quelle molto lunghe. (Ruby 2.0.0-p247) Qualcuno può confermarlo?
Plasmarob,

10
Per coloro che si chiedono perché questo esempio specifico non funziona ... ci sono 3 punti non 2 cioè [0...-4]non[0..-4]
rorofromfrance

2
@Plamarob Penso che sia più rilevante dire che chomp è 53 nanosecondi più veloce di quanto sia dire che è due volte più veloce. Quindi puoi stimare meglio il costo rispetto al valore dell'utilizzo e se potrebbe essere la cosa da ottimizzare in una determinata situazione.
cesoide,

266

Se i caratteri che desideri rimuovere sono sempre gli stessi caratteri, considera chomp:

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

I vantaggi di chompsono: nessun conteggio e il codice comunica più chiaramente cosa sta facendo.

Senza argomenti, chomprimuove la fine della riga DOS o Unix, se presente:

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

Dai commenti, c'era una domanda sulla velocità di utilizzo #chomprispetto all'utilizzo di un intervallo. Ecco un benchmark che confronta i due:

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

Risultati benchmark (utilizzando 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)

Quindi chomp è più veloce dell'uso di un intervallo, del ~ 22%.


5
Chop è anche un'opzione. È meno pignolo di ciò che viene rimosso.
Andrew Grimm,

1
Ho scoperto che è vero il contrario. La realtà è che .chomp sembra essere il doppio più veloce.
Plasmarob,

3
@Plamarob, I benchmark in Ruby sono spesso sorprendenti. Mi sbaglio così spesso che non provo più a indovinare cosa sarà più veloce. Inoltre, se la risposta venisse migliorata dai risultati del benchmark, non esitare a modificarla.
Wayne Conrad,

1
Se sto leggendo il codice giusto, l'intervallo impiega circa 53 nanosecondi in più rispetto a chomp. Potrebbe essere un trascinamento significativo in determinate situazioni, ma tenere presente la velocità assoluta (piuttosto che solo il relativo) potrebbe dirti se dovresti passare attraverso la tua base di codice e cambiare tutti i tuoi intervalli in chomps (dove applicabile). Probabilmente no.
cesoide,

1
Funziona alla grande. E puoi usare chomp!()per agire sulla stringa sul posto.
Joshua Pinter,

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

5
Si noti che questo funziona solo in Ruby 1.9. In Ruby 1.8, questo rimuoverà gli ultimi byte , non gli ultimi caratteri .
Jörg W Mittag,

5
È meglio della risposta scelta, poiché 3 punti (...) sono più facili da memorizzare poiché -n significa eliminare n caratteri dalla fine della stringa.
Lulalala,

anche "abcd" [0 ..- 2] # => "abc" mentre "abcd" [0 ...- 2] # => "ab". A mio avviso l'opzione dell'intervallo di 3 punti si traduce in un codice più autoesplicativo.
mokagio,

31

io suggerirei chop . Penso che sia stato menzionato in uno dei commenti, ma senza collegamenti o spiegazioni, quindi ecco perché penso che sia meglio:

Rimuove semplicemente l'ultimo carattere da una stringa e non è necessario specificare alcun valore perché ciò accada.

Se devi rimuovere più di un personaggio, allora chompè la soluzione migliore. Questo è ciò che i documenti di Ruby hanno da dire su chop:

Restituisce una nuova stringa con l'ultimo carattere rimosso. Se la stringa termina con \ r \ n, entrambi i caratteri vengono rimossi. L'applicazione di chop a una stringa vuota restituisce una stringa vuota. String # chomp è spesso un'alternativa più sicura, poiché lascia invariata la stringa se non termina in un separatore di record.

Sebbene questo sia usato principalmente per rimuovere separatori come l' \r\nho usato per rimuovere l'ultimo carattere da una semplice stringa, ad esempio sper rendere la parola singolare.


1
Non rimuoverebbe quel singolo ultimo personaggio? La domanda riguarda "personaggi" al plurale
maetthew,

1
Sì, hai ragione, ma chomp ('chars') rimuoverà gli ultimi 'chars'. Non mi era chiaro se l'OP volesse personaggi specifici o solo N caratteri.
Kakubei,

Sì, questa è la risposta, solo quando vuoi rimuovere solo un personaggio (che è stato il caso con me).
Quv

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

Qui nella console:

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

È efficiente? Sembra che valga la pena fare un confronto comparativo con altre risposte :)
SRack

16

Far cadere gli ultimi npersonaggi equivale a mantenere i primi length - npersonaggi.

Il supporto attivo include String#firste String#lastmetodi che forniscono un modo conveniente per conservare o eliminare il primo / ultimo ncarattere:

require 'active_support/core_ext/string/access'

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

7

se stai usando le rotaie, prova:

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

[MODIFICATO]

Per ottenere la stringa SENZA gli ultimi 2 caratteri:

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

Nota: l'ultimo carattere stringa è in n-1. Quindi, per rimuovere gli ultimi 2, usiamo n-3.


2
Questo non rimuove le ultime due lettere. Li restituisce.
JP Silvashy,

1
Non è necessario misurare prima la stringa, ruby ​​utilizza gli indici negativi dalla fine della stringa in modo nativo
Devon Parsons,

3

Puoi sempre usare qualcosa del genere

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

Dove X il numero di caratteri da rimuovere.

O con l'assegnazione / utilizzo del risultato:

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

dove Xè il numero di caratteri più uno da rimuovere.



1

Se stai bene con la creazione di metodi di classe e desideri i personaggi che tagli, prova questo:

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

Usando regex:

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

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

0

Se i personaggi che vuoi rimuovere sono sempre gli stessi, prendi in considerazione chomp:

'abc123'. chomp ('123')


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

3
la domanda era sulla rimozione degli ultimi N caratteri da una stringa, non sulla ricerca dell'ultimo carattere
unnitallman
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.