Skip to content

Instantly share code, notes, and snippets.

@JoshCheek
Created May 16, 2015 00:34
Show Gist options
  • Save JoshCheek/f516b64827fb94eb77a4 to your computer and use it in GitHub Desktop.
Save JoshCheek/f516b64827fb94eb77a4 to your computer and use it in GitHub Desktop.
json parsers
def parse_json(json)
_parse_json json.chars
end
def _parse_json(chars)
case chars.first
when '{' then parse_object chars
when '"' then parse_string chars
when '[' then parse_array chars
when /[0-9]/ then parse_number chars
end
end
def parse_object(chars)
chars.shift # {
remove_whitespace(chars)
if chars.first == '}'
chars.shift
return Hash.new
end
object = {}
loop do
key = parse_string(chars) # "key"
remove_whitespace(chars)
chars.shift # :
remove_whitespace(chars)
object[key] = _parse_json(chars) # "value"
remove_whitespace(chars)
break if chars.shift == '}'
remove_whitespace(chars)
end
object
end
def parse_string(chars)
chars.shift
string = ""
string << chars.shift until chars.first == '"'
chars.shift
string
end
def parse_array(chars)
chars.shift
remove_whitespace(chars)
if chars.first == ']'
chars.shift
return Array.new
end
ary = []
loop do
ary << _parse_json(chars)
remove_whitespace(chars)
break if chars.shift == ']'
remove_whitespace(chars)
end
ary
end
def parse_number(chars)
num_str = ""
num_str << chars.shift while [*'0'..'9'].include? chars.first
num_str.to_i
end
def remove_whitespace(chars)
chars.shift while chars.first == ' '
end
parse_json '{}' # => {}
parse_json '[]' # => []
parse_json '[1]' # => [1]
parse_json '{"a":"b","c":"DdDd","e":[""],"f":123}'
# => {"a"=>"b", "c"=>"DdDd", "e"=>[""], "f"=>123}
parse_json '{"abc" : 123, "def":"ghi" , "jkl" : [ 1 , 2 , 3 , [4,"5",6] ]}'
# => {"abc"=>123, "def"=>"ghi", "jkl"=>[1, 2, 3, [4, "5", 6]]}
require 'treetop'
Treetop.load_from_string <<GRAMMAR
grammar Json
rule document
space (object / array) space {
def to_ruby
elements[1].to_ruby
end
}
end
rule value
object / array / string / number
end
rule object
'{' space '}' {
def to_ruby
{}
end
} /
'{'
space
first:key_value_pair
rest:(space ',' space key_value_pair)*
space
'}'
{
def to_ruby
[ first.to_ruby, *rest.map(&:to_ruby)].to_h
end
def rest
super.elements.map(&:key_value_pair)
end
}
end
rule key_value_pair
key:string space ':' space value {
def to_ruby
[key.to_ruby, value.to_ruby]
end
}
end
rule array
'[' space ']' {
def to_ruby
[]
end
} /
'['
space
first:value
rest:(space ',' space value)*
space
']'
{
def to_ruby
[first.to_ruby, *rest.map(&:to_ruby)]
end
def rest
super.elements.map(&:value)
end
}
end
rule string
'"' [a-zA-Z0-9]* '"' {
def to_ruby
elements[1].text_value
end
}
end
rule number
[0-9]* {
def to_ruby
text_value.to_i
end
}
end
rule space
[ \t\n]*
end
end
GRAMMAR
def parse_json(json)
JsonParser.new.parse(json).to_ruby
end
parse_json '{}' # => {}
parse_json '[]' # => []
parse_json '[1]' # => [1]
parse_json '{"a":"b","c":"DdDd","e":[""],"f":123}'
# => {"a"=>"b", "c"=>"DdDd", "e"=>[""], "f"=>123}
parse_json '{"abc" : 123, "def":"ghi" , "jkl" : [ 1 , 2 , 3 , [4,"5",6] ]}'
# => {"abc"=>123, "def"=>"ghi", "jkl"=>[1, 2, 3, [4, "5", 6]]}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment