Quelle est la manière canonique de couper une chaîne dans Ruby sans créer une nouvelle chaîne?


185

C'est ce que j'ai maintenant - qui semble trop verbeux pour le travail qu'il fait.

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

Supposons que les jetons soient un tableau obtenu en divisant une ligne CSV. maintenant les fonctions comme strip! chomp! et. tous retournent nil si la chaîne n'a pas été modifiée

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

Quelle est la manière Ruby de dire "couper" s'il contient des espaces de début ou de fin supplémentaires sans créer de copies?

Devient plus laid si je veux faire tokens[Title].chomp!.strip!


3
Si vous allez lire des choses à partir de jetons à plusieurs reprises, il peut être plus judicieux de le prétraiter. Ie, "tokens.each {| t | t.strip!}". alors vous pouvez simplement faire "@title = tokens [Title] || ''"
glenn mcdonald

Réponses:


276

Je suppose que vous voulez:

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

La #strip!méthode retournera nilsi elle n'a rien supprimé, et la variable elle-même si elle a été supprimée.

Selon les normes Ruby, une méthode suffixée avec un point d'exclamation change la variable en place.

J'espère que cela t'aides.

Mise à jour: Ceci est la sortie de irbpour démontrer:

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

1
Hmm ... je pense toujours @title = tokens [Title] .strip! semble plus propre - c'est dommage qu'il renvoie nul au lieu de la chaîne non modifiée. À moins que quelqu'un publie un meilleur an .. vous obtenez le bit accepté.
Gishu

7
Eh bien, @title = tokens [Title] .strip fera l'affaire, mais vous en auriez une copie à la place, ce qui est bien si vous ne modifiez pas la variable tokens [Title].
Igor

9
Ruby 1.9 a tap, qui fait exactement ce que vous voulez: @ title.tap {| x | x.strip!}
timkay

2
@timkay Serait-il possible de le faire @title.tap &:strip!? Cela semble plus propre que toute autre chose.
Jon Egeland

16
Pourquoi diable reviendrait-il à nilmoins qu'il ne dépouille quelque chose? Cela a sans aucun doute dérouté une tonne de personnes (car cela n'a aucun sens).
Josh M.

54

Btw, maintenant ruby ​​prend déjà en charge juste la bande sans "!".

Comparer:

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

Il est également impossible de se strippasser des doublons. Voir les sources dans 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]

Mise à jour 1: Comme je le vois maintenant - il a été créé en 1999 année (voir rev # 372 dans SVN):

Update2: strip!ne créera pas de doublons - à la fois dans les versions 1.9.x, 2.x et trunk.


1
"il est impossible de se déshabiller sans doublons" - bien sûr, c'est possible, c'est pour ça strip!.
Karoly Horvath

@KarolyHorvath ne voyez-vous pas le code source, écrit en C? Veuillez lire attentivement ce que j'ai écrit ici concernant les doublons.
gaRex

1
Bien sûr, je le vois. Mais c'est le code source de strip. Suis-je mal compris quelque chose? Comment pourrais-je interpréter autrement «impossible de décaper sans dupliquer»?
Karoly Horvath

@KarolyHorvath, une duplication interne est toujours créée. C'est à propos de la chaîne `str = rb_str_dup (str);`
gaRex

1
Et si vous ne voulez pas de doublon, vous utilisez strip!aka rb_str_strip_bang.
Karoly Horvath

9

Il n'est pas nécessaire de supprimer et de découper à la fois, car la suppression supprimera également les retours chariot de fin - à moins que vous n'ayez changé le séparateur d'enregistrement par défaut et que c'est ce que vous grignotez.

La réponse d'Olly a déjà la manière canonique de le faire dans Ruby, bien que si vous vous surprenez à faire beaucoup cela, vous pouvez toujours définir une méthode pour cela:

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

Donnant:

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

Gardez également à l'esprit que l'instruction if empêchera @titled'être affectée si le jeton est nul, ce qui lui permettra de conserver sa valeur précédente. Si vous voulez ou ne voyez pas d'inconvénient à @titleêtre toujours affecté, vous pouvez déplacer le chèque dans la méthode et réduire davantage la duplication:

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

Comme alternative, si vous vous sentez aventureux, vous pouvez définir une méthode sur String lui-même:

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

Donner l'un des:

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

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

9

Si vous utilisez Ruby on Rails, il y a un squish

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

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

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

Si vous utilisez uniquement Ruby, vous souhaitez utiliser strip

Ici se trouve le gotcha .. dans votre cas, vous voulez utiliser la bande sans le bang!

tout en bande! renvoie certainement nil s'il n'y a pas eu d'action, il met toujours à jour la variable afin de supprimer! ne peut pas être utilisé en ligne. Si vous souhaitez utiliser la bande en ligne, vous pouvez utiliser la version sans le bang!

bande! en utilisant une approche multiligne

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

approche en bande simple ... VOTRE RÉPONSE

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

4

Je pense que votre exemple est une approche sensée, bien que vous puissiez le simplifier légèrement comme suit:

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

Alternative, vous pouvez le mettre en deux lignes:

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

3

Si vous souhaitez utiliser une autre méthode après avoir besoin de quelque chose comme ceci:

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

De cette façon, vous pouvez vous déshabiller et faire quelque chose après :)


1

Mon chemin:

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

1

Si vous avez soit ruby ​​1.9 ou activeupport, vous pouvez faire simplement

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

Ceci est vraiment cool, car il tire parti de la :tryet de la :tapméthode, qui sont les plus puissantes constructions fonctionnelles en rubis, à mon avis.

Une forme encore plus mignonne, passant des fonctions comme des symboles:

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

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

Il est tout à fait possible que je ne comprenne pas le sujet, mais cela ne répondrait-il pas à vos besoins?

" success ".strip! || "rescue" #=> "success"
"failure".strip! || "rescue" #=> "rescue"
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.