# Re: Parsing JSON (#155)

**URL:** <https://www.ruby-forum.com/t/re-parsing-json-155/128375>\
**Category:** Ruby\
**Created:** [February 7, 2008, 5:07am UTC](https://www.ruby-forum.com/t/re-parsing-json-155/128375 "2008-02-07T05:07:40Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![jameskelly](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/3ab097/32.png) [@jameskelly](https://www.ruby-forum.com/u/jameskelly)\
**Post date:** [February 7, 2008, 5:07am UTC](https://www.ruby-forum.com/t/re-parsing-json-155/128375/1 "2008-02-07T05:07:40Z")

</div>

class StringIO  
def strip!  
ch = read(1)  
ch = read(1) while /\s/ =~ ch  
ungetc ch[0]  
self  
end

def sees?(str1)  
str2 = read(str1.length)  
str2.reverse.scan(/./) {|ch| ungetc ch[0]}  
str2 == str1  
end

alias oldread read  
def read(expr,\*buffer)  
return oldread(expr,\*buffer) unless expr.is\_a? Regexp  
str = “”  
str \<\< getc until eof? or (expr =~ str) == 0  
if eof? and (expr =~ str) != 0  
str.reverse.scan(/./){|ch| ungetc ch[0]}  
return nil  
end  
maxmtch = str  
until eof?  
str \<\< getc until eof? or expr.match(str)[0] != str  
str \<\< getc until eof? or expr.match(str)[0] == str  
maxmtch = expr.match(str)[0]  
end  
str[maxmtch.length…-1].reverse.scan(/./){|ch|ungetc ch[0]}  
str = maxmtch  
if expr.match(str)[0]==str  
str  
else  
ungetc str[-1]  
str[0…-1]  
end  
end  
end

class JSONParser

def parse(str)  
parse\_next(StringIO.new(str))  
end

private

def parse\_next(strio)  
strio.strip!  
if el=number(strio)  
return el  
elsif el=string(strio)  
return el  
end  
{“true”=\>true,“false”=\>false,“null”=\>nil}.each\_pair do |k,v|  
if strio.sees? k  
strio.read k.length  
return v  
end  
end

```
if strio.sees?("{")
  obj = Hash.new
  strio.getc

  until strio.strip!.sees?("}")
    key = string(strio) or raise
    strio.strip!
    raise unless strio.read(1) == ':'
    val = parse_next(strio)
    obj[key] = val
    strio.strip!
    raise unless strio.sees?('}') or strio.read(1) == ','
  end
  strio.getc
  obj
elsif strio.read(1) == '['
  arr = Array.new
  until strio.strip!.sees?("]")
    arr << parse_next(strio)
    raise unless strio.sees?("]") or strio.read(1) == ','
  end
  strio.getc
  arr
else
  raise
end

```

end

def string(strio)  
str=strio.read(/"([^"\]|\"|\\|\/|\b|\f|\n|\r|\t|\u[a-fA-F0-9]{4})\*"/).  
to\_s.gsub(/\u([a-fA-F0-9]{4})/){$1.to\_i(16).chr}[1…-1]   
or return nil  
str.gsub!(/\["\/bfnrt]/){|s|eval(“"#{s}"”)}  
str  
end

def number(strio)  
eval (strio.read(/-?(0|[1-9]\d\*)(.\d\*)?([eE][±]?\d+)?/).to\_s)  
end  
end

```
  ____________________________________________________________________________________

```

Be a better friend, newshound, and  
know-it-all with Yahoo! Mobile. Try it now.  
[http://mobile.yahoo.com/;\_ylt=Ahu06i62sR8HDtDypao8Wcj9tAcJ](http://mobile.yahoo.com/;_ylt=Ahu06i62sR8HDtDypao8Wcj9tAcJ)
