user1130176
user1130176

Reputation: 1878

ruby regular expression to parse JSON fragment

I have a JSON fragment I need to parse:

fragment = "\"product name\":\"12 oz. Coke\", \"more keys\":\"another value\""

I want to get the value out of any key given that key's name.

I have tried:

fragment.match/\"product name\"\:\"(.+)\"/

but I get unterminated string meets end of file.

Can you help me grab the string 12 oz. Coke ?

Upvotes: 0

Views: 2086

Answers (5)

Todd A. Jacobs
Todd A. Jacobs

Reputation: 84373

Interpolate String into Valid JSON

You can use JSON#parse and a little interpolation to turn your string into a normal Ruby Hash object. A Hash will expose all sorts of useful utility methods to get at your data. For example:

# use interpolation to convert to valid JSON, then parse to Hash
fragment = "\"product name\":\"12 oz. Coke\", \"more keys\":\"another value\""
hash = JSON.parse '{%s}' % fragment
#=> {"product name"=>"12 oz. Coke", "more keys"=>"another value"}

# manipulate your new Hash object
hash['product name']
#=> "12 oz. Coke"
hash.keys
#=> ["product name", "more keys"]
hash.values
#=> ["12 oz. Coke", "another value"]

Upvotes: 1

maerics
maerics

Reputation: 156444

Just to demonstrate how you might do this using the builtin JSON parser (if that were an option):

require 'json'
fragment = '"product name":"12 oz. Coke", "more keys":"another value"'
hash = JSON.parse('{' + fragment + '}')
hash['product name'] # => "12 oz. Coke"

Upvotes: 0

ichigolas
ichigolas

Reputation: 7725

You can capture the 'value' part in the 'key-value' pattern:

str = %q("product name":"12 oz. Coke", "more keys":"another value")
str.scan /".+?":"(.+?)"/
=> [["12 oz. Coke"], ["another value"]]

http://rubular.com/r/Add4Ftf4cJ

Upvotes: 1

hirolau
hirolau

Reputation: 13911

You do not need to escape quote-signs in regexp, also, add a ?-mark to make the search lazy. This works for me:

fragment = "\"product name\":\"12 oz. Coke\", \"more keys\":\"another value\""

p fragment[/"more keys":"(.+?)"/, 1] # => "another value"
p fragment[/"product name":"(.+?)"/, 1] # => "12 oz. Coke"

Edit:

An alternative would be to put the data into a hash:

p Hash[fragment.gsub('"','').split(',').map{|x|x.strip.split(':')}]
# => {"product name"=>"12 oz. Coke", "more keys"=>"another value"}

Upvotes: 1

Ron Rosenfeld
Ron Rosenfeld

Reputation: 60224

I'm not sure about all of the formats of JSON, but one method would be to

Match the key name  -- probably best to set case insensitive
Match the separator characters
Match anything that is not a termination character into a capturing group:

/product name[\\": ]+([^\\]+)/i

Another way, using your method, would be to make the capturing group lazy. And also remember that in Ruby, you need to use \\ rather than \. So:

/"\\"product name\\":\\"(.+?)\\/i

Depending on your data, you might also need to turn on "dot matches newline"

/"\\"product name\\":\\"(.+?)\\/mi

Upvotes: 0

Related Questions