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 puis-je en obtenir 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. Il possède toutes les propriétés permettant de saisir un hachage valide dans Ruby.
Réponses:
La chaîne créée par appel
Hash#inspect
peut être reconvertie en hachage en appelanteval
. Cependant, cela nécessite que la même chose soit vraie pour tous les objets du hachage.Si je commence par le hachage
{:a => Object.new}
, alors sa représentation sous forme de chaîne est"{:a=>#<Object:0x7f66b65cf4d0>}"
, et je ne peux pas l'utilisereval
pour le transformer en hachage car la#<Object:0x7f66b65cf4d0>
syntaxe Ruby n'est pas valide.Cependant, si tout ce qui est dans le hachage est constitué de chaînes, de symboles, de nombres et de tableaux, cela devrait fonctionner, car ceux-ci ont des représentations de chaîne qui sont une syntaxe Ruby valide.
la source
eval
comme hachage en m'assurant que l'instruction ci-dessus est valide pour cette chaîne.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é. Alors imaginez si quelqu'un a injecté dans une APIrm -fr
Pour une chaîne différente, vous pouvez le faire sans utiliser de
eval
méthode dangereuse :la source
JSON.parse(hash_as_string.gsub("=>", ":").gsub(":nil,", ":null,"))
Une méthode rapide et sale serait
Mais cela a de graves implications pour la sécurité.
Il exécute tout ce qu'il est passé, vous devez être sûr à 110% (comme dans, au moins aucune entrée utilisateur n'importe où en cours de route), il ne contiendrait que des hachages correctement formés ou des bugs inattendus / horribles créatures de l'espace pourraient commencer à apparaître.
la source
Peut-être YAML.load?
la source
Ce petit extrait de code le fera, mais je ne peux pas le voir fonctionner avec un hachage imbriqué. Je pense que c'est plutôt mignon
Étapes 1. J'élimine les '{', '}' et les ':' 2. Je divise sur la chaîne partout où elle trouve un ',' 3. Je divise chacune des sous-chaînes qui ont été créées avec le fractionnement, chaque fois qu'il trouve a '=>'. Ensuite, je crée un hachage avec les deux côtés du hachage que je viens de séparer. 4. Il me reste un tableau de hachages que je fusionne ensuite.
EXEMPLE D'ENTREE: "{: user_id => 11,: blog_id => 2,: comment_id => 1}" RESULT OUTPUT: {"user_id" => "11", "blog_id" => "2", "comment_id" = > "1"}
la source
{}:
caractères des valeurs à l'intérieur du hachage stringifié?Les solutions jusqu'à présent couvrent certains cas, mais en manquent (voir ci-dessous). Voici ma tentative de conversion plus approfondie (sûre). Je connais un cas d'angle que cette solution ne gère pas, à savoir les symboles à un seul caractère composés de caractères impairs, mais autorisés. Par exemple,
{:> => :<}
un hachage ruby valide.J'ai également mis ce code sur github . Ce code commence par une chaîne de test pour exercer toutes les conversions
Voici quelques notes sur les autres solutions ici
eval
ce qui est trop effrayant pour moi (comme le souligne à juste titre Toms).la source
:nil
à:null
pour gérer cette bizarrerie particulière.J'ai eu le même problème. Je stockais un hash dans Redis. Lors de la récupération de ce hachage, il s'agissait d'une chaîne. Je ne voulais pas appeler pour des
eval(str)
raisons de sécurité. Ma solution était d'enregistrer le hachage sous forme de chaîne json au lieu d'une chaîne de hachage ruby. Si vous en avez la possibilité, utiliser json est plus simple.TL; DR: utiliser
to_json
etJSON.parse
la source
to_json
etJSON.parse
Je préfère abuser d'ActiveSupport :: JSON. Leur approche consiste à convertir le hachage en yaml, puis à le charger. Malheureusement, la conversion en yaml n'est pas simple et vous voudrez probablement l'emprunter à AS si vous n'avez pas déjà AS dans votre projet.
Nous devons également convertir tous les symboles en clés de chaîne régulières car les symboles ne sont pas appropriés dans JSON.
Cependant, il est incapable de gérer les hachages contenant une chaîne de date (nos chaînes de date finissent par ne pas être entourées de chaînes, c'est là que le gros problème entre en jeu):
string = '{' last_request_at ': 28/12/2011 23:00:00 UTC}'
ActiveSupport::JSON.decode(string.gsub(/:([a-zA-z])/,'\\1').gsub('=>', ' : '))
Se traduirait par une erreur de chaîne JSON non valide lorsqu'il essaie d'analyser la valeur de date.
J'adorerais des suggestions sur la façon de gérer cette affaire
la source
ActiveSupport::JSON.decode(response.body, symbolize_keys: true)
fonctionne dans les rails 4.1 et prend en charge les symboles sans guillemets {: a => 'b'}
ajoutez simplement ceci au dossier des initialiseurs:
la source
J'ai construit un hash_parser gem qui vérifie d'abord si un hachage est sûr ou n'utilise pas de
ruby_parser
gem. Seulement alors, il applique leeval
.Vous pouvez l'utiliser comme
Les tests de https://github.com/bibstha/ruby_hash_parser/blob/master/test/test_hash_parser.rb vous donnent plus d'exemples des choses que j'ai testées pour m'assurer que eval est sûr.
la source
Veuillez considérer cette solution. Bibliothèque + spécifications:
Fichier
lib/ext/hash/from_string.rb
::Fichier
spec/lib/ext/hash/from_string_spec.rb
::la source
it "generally works"
mais pas nécessairement? Je serais plus verbeux dans ces tests.it "converts strings to object" { expect('...').to eql ... }
it "supports nested objects" { expect('...').to eql ... }
Je suis venu à cette question après avoir écrit une ligne à cet effet, donc je partage mon code au cas où cela aiderait quelqu'un. Fonctionne pour une chaîne avec un seul niveau de profondeur et des valeurs vides possibles (mais pas nulles), comme:
Le code est:
la source
Ran sur un problème similaire nécessitant l'utilisation de eval ().
Ma situation, je tirais des données d'une API et les écrivais dans un fichier localement. Puis être en mesure d'extraire les données du fichier et d'utiliser le Hash.
J'ai utilisé IO.read () pour lire le contenu du fichier dans une variable. Dans ce cas, IO.read () le crée en tant que String.
Puis utilisé eval () pour convertir la chaîne en un Hash.
Aussi juste pour mentionner que IO est un ancêtre de File. Vous pouvez donc également utiliser File.read à la place si vous le souhaitez.
la source