2009-06-24 7 views
0

Ich habe eine Karte von anderen mit Datenstruktur wie folgt generiert:Symbol Ersatz in Ruby

x = {"city": "London", "country": "England", "region": "Europe"} 

Ich möchte die Daten in Ruby manipulieren. Um Ruby verständlich zu machen, dass es eine Karte ist, muss ich alle ":" durch "=>" ersetzen. Gibt es einen schnellen Weg, dies in einer Zeile zu erreichen?

+0

Was Sie versuchen zu erreichen, ist nicht klar. Sind die Daten in einer Datei? Offensichtlich kann die obige Zeile nicht schon Ruby sein –

+0

Es ist nicht; es sieht aus wie Python, oder vielleicht eine Python-artige selbstgebraute Syntax. Das OP möchte es in Ruby-Code umwandeln. – mipadi

+0

Ich bin auch ein bisschen verwirrt ... Wenn es in einer Textdatei ist, würden Sie offensichtlich ein Suchen und Ersetzen von: zu => ... aber das wäre zu einfach. Können Sie bitte weiter erklären, was Sie meinen? – micmoo

Antwort

5
my_text = 'x = {"city": "London", "country": "England", "region": "Europe"}' 

# Replace : with => 
ruby_code = t.gsub(':', '=>') 

# Evaluate the string as ruby code 
eval ruby_code 

# Now you can access the hash 

x['city'] # => "London" 
+3

Tun Sie dies nur, wenn Sie sicher sind, dass es weder in den Schlüsseln noch in den Werten Doppelpunkte geben wird! Wenn dies möglich ist, verwenden Sie die vorgeschlagene JSON-Methode Subba Rao. –

+0

Achten Sie auch darauf, dass Ihre Strings nichts enthalten, was eval als Rubin-Interpolation interpretieren könnte, wie '{' tun Sie das nicht ': "# {' rm -rf ~ '}"}' - das wäre schlecht – rampion

+2

Dies ist sehr unsicher und zerbrechlich. Die Verwendung von "eval" ist fast immer falsch. Subba Raos Antwort ist viel besser. –

2
'{"city": "London", "country": "England", "region": "Europe"}'.gsub!(/: /, ' => ') 

gsub! führt eine direkte globale Ersetzung der Zeichenfolge durch.

13

benötigen Sie dieses Juwel Juwel json

sudo installieren json

require 'json' 
    JSON.parse('{"city": "London", "country": "England", "region": "Europe"}') 
+1

Ich mag diese Antwort wirklich. Auch wenn es wahrscheinlich langsamer ist als Collimarcos (was ich auch mag), scheint es bei der zugrunde liegenden Bedeutung von dem, was hier passiert, viel besser zu werden. Es ist sehr unwahrscheinlich, dass sich das JSON-Format für Maps/Hashes ändert, also gibt es keinen wirklichen technischen Vorteil. Es fühlt sich einfach gut an. –

+2

Es vermeidet auch die Ausführung der fremden Eingabe als Code. – user37011

+1

Wenn irgendetwas in der Eingabe schief geht, wird auf diese Weise ein JSON-Parse-Fehler ausgelöst. Der gsub-Weg wird, naja, könnte so ziemlich alles Mögliche! Wirklich guter Grund, diesen Weg zu bevorzugen. –

0

eine weitere Alternative zu installieren, wenn Sie Ihre Anfälligkeit für #eval minimieren wollte (was eine rationale Sache zu tun) zu verwenden ist String#scan:

quoted = /"(?:\\.|[^\\"])*"/ 
pairs = '{"city": "London", "country": "England", "region": "Europe"}'.scan(/(#{quoted})\s*:\s*(#{quoted})/) 
hash = Hash[ *pairs.flatten.map { |q| eval q } ] 

Wir verwenden immernoch #eval, aber wir wissen, dass wir nur #eval sind, die etwas wie eine Zeichenfolge in Anführungszeichen aussieht, also sind wir sicher. Da Rubin Strings beliebigen Code (durch das Wunder der Interpolation) enthalten kann, sind wir immer noch verwundbar, aber:

# arbitrary code evaluation 
p eval('"one two #{puts %{Give me a three!}; gets.chomp} four"') 

Die sicherste Alternative ist #eval ganz zu umgehen, und eine Bibliothek verwendet für Streicher unquoting, die ‚doesn t erlauben Interpolation. Die JSON-Bibliothek (wie bereits erwähnt) ist ein großartiges Beispiel dafür. Es scheint langsamer (da es ist nicht so optimiert wie #eval ist), aber es ist eine ganze Menge viel sicherer.