87 votes

Ruby remplacement multiple de chaînes

str = "Bonjour le monde"

Résultat attendu :

"Bonjour:) le monde:("

Je peux le faire : str.gsub("", ":)").gsub("", ":(")

Y a-t-il une autre façon de faire cela en un seul appel de fonction ? Quelque chose comme :

str.gsub(['s1', 's2'], ['r1', 'r2'])

1 votes

Y a-t-il une raison pour laquelle vous voulez faire cela en une seule fois? Je préférerais rester avec votre première solution.

2 votes

@Semyon : La table de correspondance pourrait être grande ou elle pourrait être configurée au moment de l'exécution.

1 votes

Sur une note similaire, si vous vous retrouvez avec une énorme table de mappage, vous regardez essentiellement un langage de templating. Vous pouvez, dans ce cas, le convertir en un DSL et écrire un interprète (ou compilateur) pour cela.

128voto

Naren Sisodiya Points 4180

Depuis Ruby 1.9.2, String#gsub accepte un hachage comme deuxième paramètre pour le remplacement avec des clés correspondantes. Vous pouvez utiliser une expression régulière pour trouver la sous-chaîne qui doit être remplacée et passer un hachage pour les valeurs à remplacer.

Comme ceci :

'hello'.gsub(/[eo]/, 'e' => 3, 'o' => '*')    #=> "h3ll*"
'(0) 123-123.123'.gsub(/[()-,. ]/, '')    #=> "0123123123"

En Ruby 1.8.7, vous auriez obtenu le même résultat avec un bloc :

dict = { 'e' => 3, 'o' => '*' }
'hello'.gsub /[eo]/ do |match|
   dict[match.to_s]
 end #=> "h3ll*"

1 votes

Woah ! Je n'avais aucune idée ! Super contenu !

0 votes

Cool, je ne savais pas ça. Une version un peu plus agréable que Perl tr.

0 votes

Notez que cela n'est pas la même chose que d'appeler str.gsub(key, value) sur chaque élément du hachage. Si quelque chose correspond à l'expression régulière mais n'a pas d'entrée dans le hachage, cela sera supprimé.

42voto

mu is too short Points 205090

Configurer une table de correspondance :

map = {'☺' => ':)', '☹' => ':(' }

Ensuite construisez une expression régulière :

re = Regexp.new(map.keys.map { |x| Regexp.escape(x) }.join('|'))

Et enfin, gsub :

s = str.gsub(re, map)

Si vous êtes bloqué dans la version 1.8, alors :

s = str.gsub(re) { |m| map[m] }

Vous avez besoin du Regexp.escape au cas où vous voudriez remplacer quelque chose ayant un sens spécial dans une expression régulière. Ou, grâce à steenslag, vous pourriez utiliser :

re = Regexp.union(map.keys)

et les guillemets seront pris en charge pour vous.

0 votes

@steenslag: C'est une belle modification.

0 votes

String#gsub accepte les chaînes de caractères en tant que paramètre de modèle: "Le modèle est généralement une expression rationnelle; s'il est donné sous forme de chaîne, tous les méta-caractères d'expression régulière qu'il contient seront interprétés littéralement, par exemple '\\d' fera correspondre un backslash suivi de 'd', au lieu d'un chiffre.".

0 votes

@Andrew : Oui mais nous avons plusieurs chaînes à remplacer, d'où l'utilisation des expressions régulières.

38voto

Nathan Manousos Points 2968

Vous pourriez faire quelque chose comme ceci :

replacements = [ ["☺", ":)"], ["☹", ":("] ]
replacements.each {|replacement| str.gsub!(replacement[0], replacement[1])}

Il pourrait y avoir une solution plus efficace, mais cela rend au moins le code un peu plus propre

2 votes

N'est-il pas censé être replacements.each ?

4 votes

Il s'agit simplement de quelque chose de plus compliqué et plus lent.

0 votes

Quand j'ai ceci comme dernière ligne d'une méthode, quelle serait la valeur de retour implicite ? str ou quelque chose d'autre ?

20voto

lsaffie Points 711

En retard à la fête mais si vous vouliez remplacer certains caractères par un seul, vous pourriez utiliser une regex

string_to_replace.gsub(/_|,| /, '-')

Dans cet exemple, gsub remplace les tirets bas (_), les virgules (,) ou les espaces ( ) par un tiret (-)

4 votes

Cela serait encore mieux comme ceci : string_to_replace.gsub(/[_- ]/, '-')

8voto

Diego Dorado Points 128

Une autre façon simple et pourtant facile à lire est la suivante :

str = '12 ene 2013'
map = {'ene' => 'jan', 'abr'=>'apr', 'dic'=>'dec'}
map.each {|k,v| str.sub!(k,v)}
puts str # '12 jan 2013'

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X