Ich habe eine Zeichenfolge, die wie ein Hash aussieht:
"{ :key_a => { :key_1a => 'value_1a', :key_2a => 'value_2a' }, :key_b => { :key_1b => 'value_1b' } }"
Wie bekomme ich einen Hash daraus? mögen:
{ :key_a => { :key_1a => 'value_1a', :key_2a => 'value_2a' }, :key_b => { :key_1b => 'value_1b' } }
Die Zeichenfolge kann eine beliebige Verschachtelungstiefe aufweisen. Es hat alle Eigenschaften, wie ein gültiger Hash in Ruby eingegeben wird.
Antworten:
Die durch Aufrufen erstellte Zeichenfolge kann durch Aufrufen
Hash#inspect
wieder in einen Hash umgewandelt werdeneval
. Dies setzt jedoch voraus, dass dies für alle Objekte im Hash gilt.Wenn ich mit dem Hash beginne
{:a => Object.new}
, ist seine Zeichenfolgendarstellung"{:a=>#<Object:0x7f66b65cf4d0>}"
und ich kann ihn nichteval
wieder in einen Hash umwandeln, da#<Object:0x7f66b65cf4d0>
die Ruby-Syntax nicht gültig ist.Wenn der Hash jedoch nur Zeichenfolgen, Symbole, Zahlen und Arrays enthält, sollte dies funktionieren, da diese Zeichenfolgendarstellungen mit gültiger Ruby-Syntax enthalten.
quelle
eval
als Hash verwendet werden soll, indem ich sicherstelle, dass die obige Anweisung für diese Zeichenfolge gültig ist.eval
am falschen Ort ist eine große Sicherheitslücke. Alles innerhalb der Zeichenfolge wird ausgewertet. Stellen Sie sich also vor, in eine API würde jemand injizierenrm -fr
Für verschiedene Zeichenfolgen können Sie dies tun, ohne eine gefährliche
eval
Methode anzuwenden:quelle
JSON.parse(hash_as_string.gsub("=>", ":").gsub(":nil,", ":null,"))
Schnelle und schmutzige Methode wäre
Dies hat jedoch schwerwiegende Auswirkungen auf die Sicherheit.
Es führt alles aus, was übergeben wird. Sie müssen zu 110% sicher sein (wie in, zumindest keine Benutzereingaben irgendwo auf dem Weg), dass es nur richtig geformte Hashes enthält oder unerwartete Fehler / schreckliche Kreaturen aus dem Weltraum auftauchen könnten.
quelle
Vielleicht YAML.load?
quelle
Dieses kurze kleine Snippet wird es tun, aber ich kann nicht sehen, dass es mit einem verschachtelten Hash funktioniert. Ich finde es aber ziemlich süß
Schritte 1. Ich eliminiere das '{', '}' und das ':' 2. Ich teile die Zeichenfolge überall dort auf, wo sie ein ',' findet. 3. Ich teile jede der Teilzeichenfolgen, die mit der Teilung erstellt wurden, wann immer sie gefunden wird a '=>'. Dann erstelle ich einen Hash mit den beiden Seiten des Hash, die ich gerade getrennt habe. 4. Ich habe eine Reihe von Hashes, die ich dann zusammenführe.
BEISPIELEINGABE: "{: user_id => 11 ,: blog_id => 2 ,: comment_id => 1}" ERGEBNISAUSGABE: {"user_id" => "11", "blog_id" => "2", "comment_id" = > "1"}
quelle
{}:
Zeichen von Werten innerhalb des stringifizierten Hashs entfernen?Die bisherigen Lösungen decken einige Fälle ab, übersehen jedoch einige (siehe unten). Hier ist mein Versuch einer gründlicheren (sicheren) Konvertierung. Ich kenne einen Eckfall, den diese Lösung nicht behandelt, nämlich einzelne Zeichensymbole, die aus ungeraden, aber erlaubten Zeichen bestehen. Zum Beispiel
{:> => :<}
ist ein gültiger Ruby-Hash.Ich habe diesen Code auch auf Github veröffentlicht . Dieser Code beginnt mit einer Testzeichenfolge, um alle Konvertierungen durchzuführen
Hier einige Hinweise zu den anderen Lösungen
eval
was mir zu beängstigend ist (wie Toms zu Recht betont ).quelle
:nil
,:null
um mit dieser besonderen Verrücktheit umzugehen .Ich hatte das gleiche Problem. Ich habe einen Hash in Redis gespeichert. Beim Abrufen dieses Hashs war es eine Zeichenfolge. Ich wollte
eval(str)
aus Sicherheitsgründen nicht anrufen . Meine Lösung bestand darin, den Hash als JSON-String anstelle eines Ruby-Hash-Strings zu speichern. Wenn Sie die Option haben, ist die Verwendung von json einfacher.TL; DR: verwenden
to_json
undJSON.parse
quelle
to_json
undJSON.parse
Ich bevorzuge es, ActiveSupport :: JSON zu missbrauchen. Ihr Ansatz besteht darin, den Hash in Yaml umzuwandeln und ihn dann zu laden. Leider ist die Konvertierung in yaml nicht einfach und Sie möchten sie wahrscheinlich von AS ausleihen, wenn Sie AS noch nicht in Ihrem Projekt haben.
Wir müssen auch alle Symbole in reguläre String-Schlüssel konvertieren, da Symbole in JSON nicht geeignet sind.
Es ist jedoch nicht in der Lage, Hashes zu verarbeiten, die eine Datumszeichenfolge enthalten (unsere Datumszeichenfolgen werden letztendlich nicht von Zeichenfolgen umgeben, weshalb das große Problem auftritt):
string = '{' last_request_at ': 2011-12-28 23:00:00 UTC}'
ActiveSupport::JSON.decode(string.gsub(/:([a-zA-z])/,'\\1').gsub('=>', ' : '))
Würde zu einem ungültigen JSON-Zeichenfolgenfehler führen, wenn versucht wird, den Datumswert zu analysieren.
Würde mich über Vorschläge zur Behandlung dieses Falls freuen
quelle
ActiveSupport::JSON.decode(response.body, symbolize_keys: true)
funktioniert in Rails 4.1 und unterstützt Symbole ohne Anführungszeichen {: a => 'b'}
Fügen Sie dies einfach dem Initialisierungsordner hinzu:
quelle
Ich habe einen gem hash_parser erstellt , der zuerst prüft, ob ein Hash sicher ist oder nicht
ruby_parser
gem. Nur dann gilt daseval
.Sie können es als verwenden
Die Tests in https://github.com/bibstha/ruby_hash_parser/blob/master/test/test_hash_parser.rb geben Ihnen weitere Beispiele für die Dinge, die ich getestet habe, um sicherzustellen, dass die Bewertung sicher ist.
quelle
Bitte beachten Sie diese Lösung. Bibliothek + Spezifikation:
Datei:
lib/ext/hash/from_string.rb
:Datei:
spec/lib/ext/hash/from_string_spec.rb
:quelle
it "generally works"
aber nicht unbedingt? Ich würde in diesen Tests ausführlicher sein.it "converts strings to object" { expect('...').to eql ... }
it "supports nested objects" { expect('...').to eql ... }
Ich bin auf diese Frage gekommen, nachdem ich zu diesem Zweck einen Einzeiler geschrieben habe, und teile meinen Code, falls er jemandem hilft. Funktioniert für einen String mit nur einer Ebenentiefe und möglichen leeren Werten (aber nicht Null) wie:
Der Code lautet:
quelle
Ist auf ein ähnliches Problem gestoßen, bei dem eval () verwendet werden musste.
In meiner Situation habe ich einige Daten aus einer API abgerufen und lokal in eine Datei geschrieben. Dann können Sie die Daten aus der Datei ziehen und den Hash verwenden.
Ich habe IO.read () verwendet, um den Inhalt der Datei in eine Variable einzulesen. In diesem Fall erstellt IO.read () es als String.
Verwenden Sie dann eval (), um den String in einen Hash zu konvertieren.
Auch nur um zu erwähnen, dass IO ein Vorfahr von File ist. Sie können also auch File.read verwenden, wenn Sie möchten.
quelle