Qual è il modo canonico di tagliare una stringa in Ruby senza creare una nuova stringa?


182

Questo è quello che ho ora - che sembra troppo dettagliato per il lavoro che sta facendo.

@title        = tokens[Title].strip! || tokens[Title] if !tokens[Title].nil?

Supponiamo che i token siano un array ottenuto dividendo una linea CSV. ora le funzioni come strip! Chomp! et. tutti restituiscono zero se la stringa non è stata modificata

"abc".strip!    # => nil
" abc ".strip!  # => "abc"

Qual è il modo in cui dice Ruby tagliarlo se contiene spazi iniziali o finali extra senza creare copie?

Diventa più brutto se voglio fare tokens[Title].chomp!.strip!


3
Se stai leggendo cose dai token ripetutamente, potrebbe avere più senso pre-elaborarlo. Vale a dire "tokens.each {| t | t.strip!}". allora puoi semplicemente fare "@title = tokens [Title] || ''"
glenn mcdonald

Risposte:


272

Immagino che tu voglia:

@title = tokens[Title]
@title.strip!

Il #strip!metodo restituirà nilse non ha rimosso nulla e la stessa variabile se è stata rimossa.

Secondo gli standard di Ruby, un metodo con un punto esclamativo modifica la variabile in atto.

Spero che questo ti aiuti.

Aggiornamento: questo viene emesso irbper dimostrare:

>> @title = "abc"
=> "abc"
>> @title.strip!
=> nil
>> @title
=> "abc"
>> @title = " abc "
=> " abc "
>> @title.strip!
=> "abc"
>> @title
=> "abc"

1
Hmm .. penso ancora @title = tokens [Title] .strip! sembra più pulito - è un peccato che restituisca zero invece della stringa non modificata. A meno che qualcuno non pubblichi un migliore ans .. stai ricevendo il bit accettato.
Gishu,

7
Bene, @title = tokens [Title] .strip farà il trucco, ma avresti invece una copia, il che va bene se mantieni la variabile token [Title] intatta.
Igor,

9
Ruby 1.9 ha tap, che fa esattamente quello che vuoi: @ title.tap {| x | x.strip!}
timkay

2
@timkay Sarebbe possibile farlo @title.tap &:strip!? Sembra più pulito di ogni altra cosa.
Jon Egeland,

16
Perché nel mondo sarebbe tornato nilse non avesse spogliato qualcosa? Ciò ha indubbiamente confuso un sacco di persone (dal momento che non ha senso).
Josh M.

53

A proposito, ora ruby ​​supporta già solo lo strip senza "!".

Confrontare:

p "abc".strip! == " abc ".strip!  # false, because "abc".strip! will return nil
p "abc".strip == " abc ".strip    # true

Inoltre è impossibile stripsenza duplicati. Vedi fonti in string.c:

static VALUE
rb_str_strip(VALUE str)
{
    str = rb_str_dup(str);
    rb_str_strip_bang(str);
    return str;
}

ruby 1.9.3p0 (30-10-2011) [i386-mingw32]

Aggiornamento 1: Come vedo ora - è stato creato nell'anno 1999 (vedi rev # 372 in SVN):

Update2: strip!non creerà duplicati, sia nelle versioni 1.9.x, 2.xe trunk.


1
"è impossibile spogliarsi senza duplicati" - ovviamente è possibile, ecco a cosa strip!serve.
Karoly Horvath,

@KarolyHorvath non vedi il codice sorgente, scritto in C? Leggete attentamente, quello che ho scritto qui riguardo ai duplicati.
gaRex,

1
Certo che lo vedo. Ma questo è il codice sorgente di strip. Sto fraintendendo qualcosa? In quale altro modo potrei interpretare "impossibile lo stripping senza duplicati"?
Karoly Horvath,

@KarolyHorvath viene sempre creato un duplicato interno. Riguarda la stringa `str = rb_str_dup (str);`
gaRex,

1
E se non vuoi un duplicato, usi strip!aka rb_str_strip_bang.
Karoly Horvath,

9

Non è necessario sia strip che chomp poiché strip rimuoverà anche i ritorni a capo finali - a meno che tu non abbia modificato il separatore di record predefinito e questo è ciò che stai chomp.

La risposta di Olly ha già il modo canonico di farlo in Ruby, sebbene se ti ritrovi a farlo molto potresti sempre definire un metodo per farlo:

def strip_or_self!(str)
  str.strip! || str
end

Dando:

@title = strip_or_self!(tokens[Title]) if tokens[Title]

Inoltre, tieni presente che l'istruzione if impedisce @title di essere assegnata se il token è nullo, il che comporterà il mantenimento del valore precedente. Se vuoi o non ti dispiace @titleessere assegnato sempre puoi spostare il segno di spunta nel metodo e ridurre ulteriormente la duplicazione:

def strip_or_self!(str)
  str.strip! || str if str
end

In alternativa, se ti senti avventuroso, puoi definire un metodo su String stesso:

class String
  def strip_or_self!
    strip! || self
  end
end

Dare uno di:

@title = tokens[Title].strip_or_self! if tokens[Title]

@title = tokens[Title] && tokens[Title].strip_or_self!

9

Se stai usando Ruby on Rails c'è uno squish

> @title = " abc "
 => " abc " 

> @title.squish
 => "abc"
> @title
 => " abc "

> @title.squish!
 => "abc"
> @title
 => "abc" 

Se stai usando solo Ruby, vuoi usare strip

Qui sta il gotcha .. nel tuo caso vuoi usare la striscia senza il botto!

mentre spogliati! certamente restituisce zero se non ci sono azioni aggiorna comunque la variabile quindi striscia! non può essere utilizzato in linea. Se vuoi usare la strip inline puoi usare la versione senza il botto!

striscia! utilizzando l'approccio multilinea

> tokens["Title"] = " abc "
 => " abc "
> tokens["Title"].strip!
 => "abc"
> @title = tokens["Title"]
 => "abc"

strip approccio a linea singola ... LA TUA RISPOSTA

> tokens["Title"] = " abc "
 => " abc "
> @title = tokens["Title"].strip if tokens["Title"].present?
 => "abc"

4

Penso che il tuo esempio sia un approccio sensato, anche se potresti semplificarlo leggermente come:

@title = tokens[Title].strip! || tokens[Title] if tokens[Title]

In alternativa potresti metterlo su due righe:

@title = tokens[Title] || ''
@title.strip!

3

Se vuoi usare un altro metodo dopo aver bisogno di qualcosa del genere:

( str.strip || str ).split(',')

In questo modo puoi spogliarti e fare ancora qualcosa dopo :)


1

A modo mio:

> (@title = " abc ").strip!
 => "abc" 
> @title
 => "abc" 

1

Se hai ruby ​​1.9 o activesupport, puoi farlo semplicemente

@title = tokens[Title].try :tap, &:strip!

Questo è davvero bello, in quanto sfrutta il :trye il:tap metodo, che sono le più potenti costrutti funzionali in rubino, a mio parere.

Una forma ancora più intelligente, passando funzioni come simboli del tutto:

@title = tokens[Title].send :try, :tap, &:strip!

-1
@title = tokens[Title].strip! || tokens[Title]

È del tutto possibile che non capisco l'argomento, ma questo non farebbe ciò di cui hai bisogno?

" success ".strip! || "rescue" #=> "success"
"failure".strip! || "rescue" #=> "rescue"
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.