143 votes

Comment convertir un objet String en un objet Hash ?

J'ai une chaîne qui ressemble à un hachage :

"{ :key_a => { :key_1a => 'value_1a', :key_2a => 'value_2a' }, :key_b => { :key_1b => 'value_1b' } }"

Comment je peux en tirer un Hash ? Comme :

{ :key_a => { :key_1a => 'value_1a', :key_2a => 'value_2a' }, :key_b => { :key_1b => 'value_1b' } }

La chaîne peut avoir n'importe quelle profondeur d'imbrication. Elle possède toutes les propriétés de typage d'un Hash valide en Ruby.

0 votes

Je pense qu'Eval va faire quelque chose ici. Je vais d'abord tester. J'ai posté la question trop tôt, je pense :)

0 votes

Ohh oui, il suffit de le passer à l'évaluation :)

179voto

zolter Points 2188

Pour les différentes chaînes, vous pouvez le faire sans utiliser de dangereux eval méthode :

hash_as_string = "{\"0\"=>{\"answer\"=>\"1\", \"value\"=>\"No\"}, \"1\"=>{\"answer\"=>\"2\", \"value\"=>\"Yes\"}, \"2\"=>{\"answer\"=>\"3\", \"value\"=>\"No\"}, \"3\"=>{\"answer\"=>\"4\", \"value\"=>\"1\"}, \"4\"=>{\"value\"=>\"2\"}, \"5\"=>{\"value\"=>\"3\"}, \"6\"=>{\"value\"=>\"4\"}}"
JSON.parse hash_as_string.gsub('=>', ':')

2 votes

Cette réponse doit être choisie pour éviter d'utiliser eval.

5 votes

Vous devriez également remplacer nils, f.e. JSON.parse(hash_as_string.gsub("=>", ":").gsub(":nil,", ":null,"))

1 votes

Ne fonctionne pas avec les symboles, malheureusement...

142voto

Toms Mikoss Points 2053

Une méthode simple et rapide serait

eval("{ :key_a => { :key_1a => 'value_1a', :key_2a => 'value_2a' }, :key_b => { :key_1b => 'value_1b' } }") 

Mais cela a de graves répercussions sur la sécurité.
Il exécute tout ce qui lui est passé, vous devez être sûr à 110% (c'est-à-dire qu'il ne doit pas y avoir de saisie de l'utilisateur) qu'il ne contiendra que des hachages correctement formés ou des bogues inattendus/des créatures horribles de l'espace pourraient commencer à apparaître.

16 votes

J'ai un sabre laser avec moi. Je peux m'occuper de ces créatures et de ces insectes. :)

12 votes

L'utilisation d'EVAL peut être dangereuse ici, selon mon professeur. Eval prend n'importe quel code ruby et l'exécute. Le danger ici est analogue au danger d'injection SQL. Gsub est préférable.

9 votes

Exemple de chaîne de caractères montrant pourquoi le professeur de David a raison : '{:surprise => "#{system \"rm -rf * \"}"}''.

84voto

Ken Bloom Points 27197

La chaîne créée en appelant Hash#inspect peut être transformé en un hash en appelant eval sur elle. Toutefois, il faut pour cela qu'il en soit de même pour tous les objets du hachage.

Si je commence avec le hachage {:a => Object.new} alors sa représentation en chaîne est "{:a=>#<Object:0x7f66b65cf4d0>}" et je ne peux pas utiliser eval pour le retransformer en hash car #<Object:0x7f66b65cf4d0> n'est pas une syntaxe Ruby valide.

Cependant, si le hachage ne contient que des chaînes de caractères, des symboles, des nombres et des tableaux, cela devrait fonctionner, car ces éléments ont des représentations de chaînes de caractères qui sont des syntaxes Ruby valides.

0 votes

"si tout ce qui est dans le hachage est constitué de chaînes de caractères, de symboles et de chiffres,". Cela en dit long. Donc je peux vérifier la validité d'une chaîne de caractères pour être eval uated as a hash by making sure that the above statement is valid for that string.

1 votes

Oui, mais pour cela, il faut soit un analyseur syntaxique Ruby complet, soit savoir d'où vient la chaîne de caractères en premier lieu et savoir qu'il ne peut générer que des chaînes de caractères, des symboles et des nombres. (Voir aussi la réponse de Toms Mikoss sur la confiance dans le contenu de la chaîne).

17 votes

Faites attention à l'endroit où vous l'utilisez. Utilisation de eval au mauvais endroit est une énorme faille de sécurité. Tout ce qui se trouve à l'intérieur de la chaîne sera évalué. Donc imaginez si dans une API quelqu'un injectait rm -fr

26voto

silent Points 2156

Peut-être YAML.load ?

0 votes

(la méthode de chargement supporte les chaînes de caractères)

5 votes

Cela nécessite une représentation de la chaîne totalement différente, mais c'est beaucoup, beaucoup plus sûr. (Et la représentation de la chaîne est tout aussi facile à générer -- il suffit d'appeler #to_yaml, plutôt que #inspect).

0 votes

Wow. Je ne savais pas que c'était si facile d'analyser des chaînes de caractères avec yaml. Il prend ma chaîne de commandes bash linux qui génère des données et la transforme intelligemment en un ruby Hash sans aucune manipulation du format de la chaîne.

23voto

jackquack Points 1246

Ce petit extrait le fera, mais je ne le vois pas fonctionner avec un hachage imbriqué. Je pense que c'est assez mignon cependant

STRING.gsub(/[{}:]/,'').split(', ').map{|h| h1,h2 = h.split('=>'); {h1 => h2}}.reduce(:merge)

Étapes 1. J'élimine les '{', '}' et les ':'. 2. Je divise la chaîne de caractères chaque fois qu'elle trouve un ','. 3. Je divise chacune des sous-chaînes qui ont été créées avec la division, chaque fois qu'il trouve un '=>'. Ensuite, je crée un hachage avec les deux côtés du hachage que je viens de diviser. 4. Je me retrouve avec un tableau de hachages que je fusionne ensuite.

EXEMPLE INPUT : "{:user_id=>11, :blog_id=>2, :comment_id=>1}" RESULTAT : {"user_id"=>"11", "blog_id"=>"2", "comment_id"=>"1"}

1 votes

C'est un oneliner de malade ! :) +1

3 votes

Cela ne va-t-il pas aussi enlever {}: personnages de valeurs à l'intérieur de la chaîne de hachage ?

0 votes

@VladimirPanteleev Vous avez raison, ça le ferait. Bien vu ! Vous pouvez faire mes revues de code tous les jours :)

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