2010-01-13 13 views
22

Ich verstehe, dass in JSON Schlüssel in doppelten Anführungszeichen umgeben sein sollen. Allerdings verwende ich eine Datenquelle, die sie nicht zitiert, was dazu führt, dass der Ruby-JSON-Parser einen Fehler auslöst. Gibt es eine Möglichkeit, "nicht-striktes" Parsen durchzuführen?JSON ohne notierte Schlüssel analysieren

Beispiel:

>> JSON.parse('{name:"hello", age:"23"}') 
JSON::ParserError: 618: unexpected token at '{name:"hello", age:"23"}' 
    from /Library/Ruby/Gems/1.8/gems/json-1.1.7/lib/json/common.rb:122:in `parse' 
    from /Library/Ruby/Gems/1.8/gems/json-1.1.7/lib/json/common.rb:122:in `parse' 
    from (irb):5 
>> JSON.parse('{"name":"hello", "age":"23"}') 
=> {"name"=>"hello", "age"=>"23"} 
>> 

(Ich habe versucht, einen regulären Ausdruck, die Anführungszeichen vor dem Parsen hinzufügen verwenden, aber konnte es nicht voll funktionsfähig).

+9

Wenn es nicht JSON ist, ist es nicht JSON. Es mag oberflächlich ähnlich aussehen, aber die richtige Lösung ist es, die Quelle so zu reparieren, dass sie JSON statt von etwas gibt, das ein bisschen wie JSON aussieht, aber nicht ist. –

+0

Leider habe ich keine Kontrolle über die Quelle, es ist von einer dritten Partei. –

+0

http://www.google.com/ig/calculator?hl=de&q=100AUD=?USD zum Beispiel erfordert, wonach er fragt. @floyd hat die Lösung unten - und ist akzeptabel – Rabbott

Antwort

15

Wenn die Daten ziemlich gut andere gebildet als eine einfache regex tun könnte es:

irb(main):009:0> '{name:"hello", age:"23"}'.gsub(/([a-z]+):/, '"\1":') 
=> "{\"name\":\"hello\", \"age\":\"23\"}" 
+5

'{Name:" Hallo ", Alter:" 23 "} '.gsub (/ ([\ w] +): /,' "\ 1": ') 'macht es ein wenig robuster! – ankimal

+3

Fällt kläglich aus, wenn der Wert ein Zeitstempel ist. Zum Beispiel {Name: "Hallo", Uhrzeit: "12:59:59"} – Prabhakar

6

Interessanterweise ist Ihr Beispiel gültig Ruby 1.9 Hash-Syntax. Wenn Ihre Daten wirklich so einfach sind (keine Leerzeichen oder andere Sonderzeichen in den Schlüsselnamen) und Sie sie in einem sicheren Kontext verarbeiten können, können Sie einfach eval es.

irb(main):001:0> eval '{name:"hello", age:"23"}' 
=> {:name=>"hello", :age=>"23"} 

Diese Sie Symbole als Schlüssel gibt, so nachbearbeiten, wenn man sie in Strings zu machen brauchen:

irb(main):002:0> eval('{name:"hello", age:"23"}').reduce({}) {|h,(k,v)| h[k.to_s] = v; h} 
=> {"name"=>"hello", "age"=>"23"} 
+1

Danke dafür, obwohl ich seit 1.8.7 im Moment keine Option bin. –

+0

Sehr saubere Lösung! Vielen Dank. Viel sauberer, um diese Informationen von Google zu nutzen, anstatt ein anderes Juwel zu jagen. – ylluminate

+5

Das kann sehr gefährlich sein ... (zB wenn Sie vom Server '{a: 1}; \' rm -rf/\ '') – ghayes

1

(Beantwortung meiner Frage) Die Schnipsel, die gebucht FLOYD war ähnlich zu dem, was ich versuchte - es versagte, weil einige meiner Strings Doppelpunkte enthalten. Aber ich blieb und fand eine Lösung:

gsub(/([\{|\,}])\s*([a-zA-Z]+):/, '\1 "\2":') 
+0

Das Problem ist, dass Ihre Regex auch Instanzen von "key =" in einem zitierten Wert ersetzen wird, den Sie nicht möchten. –

2
gsub(/(\w+)\s*:/, '"\1":') 

funktionierte besser als

gsub(/([a-z]+):/, '"\1":') 

Wenn es Leerzeichen oder Großbuchstaben hatte, es ist fehlgeschlagen.

8

Ich habe das gleiche Problem mit einem Drittanbieter-Daten-Feed, aber meins gibt eine kompliziertere JSON-ähnliche Antwort, die die gsub-Lösungen nicht behandeln. Nach einigen Recherchen scheint es sich bei diesen Daten-Feeds tatsächlich um JavaScript-Objektliterale zu handeln, bei denen die Schlüssel nicht in Anführungszeichen gesetzt werden müssen.

Um das Problem zu beheben, habe ich die execjs gem und installiert node.js (therubyracer Edelstein würde wahrscheinlich auch funktionieren). Nach der Ausführung gibt der folgende Befehl einen korrekt analysierten Ruby-Hash zurück.

ExecJS.eval('{name:"hello", age:"23"}') 
=> {"name"=>"hello", "age"=>"23"} 
0

Dies ist, wie ich es zu lösen gehabt haben:

JSON.parse(broken_json_string.gsub(/'([^']+)':/, '"\1":')) 

Einige der oben genannten übernimmt nur die Tasten Buchstaben enthalten; einige von uns enthielten Unterstriche, Leerzeichen usw. Einfacher gesagt "jedes Zeichen, das kein einfaches Zitat ist" (in unserem Fall wurden alle Schlüssel in einfache Anführungszeichen gesetzt).