Re: Parsing JSON (#155)

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