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