fork download
  1. class MyJSONError < StandardError; end
  2.  
  3. # - - - - - - - - - - -
  4.  
  5. def is_space_char(text, ptr = 0)
  6. !!(text[ptr]=~/^\s/)
  7. end
  8.  
  9. def is_digit_char(text, ptr = 0)
  10. !!(text[ptr]=~/^[0-9]/)
  11. end
  12.  
  13. # - - - - - - - - - - -
  14.  
  15. def json_parse_true(text, ptr = 0)
  16. if text[ptr..(ptr+3)] == 'true'
  17. return [true, ptr+4]
  18. else
  19. raise MyJSONError.new("invalid keyword at #{ptr}")
  20. end
  21. end
  22.  
  23. def json_parse_false(text, ptr = 0)
  24. if text[ptr..(ptr+4)] == 'false'
  25. return [false, ptr+5]
  26. else
  27. raise MyJSONError.new("invalid keyword at #{ptr}")
  28. end
  29. end
  30.  
  31. def json_parse_null(text, ptr = 0)
  32. if text[ptr..(ptr+3)] == 'null'
  33. return [nil, ptr+4]
  34. else
  35. raise MyJSONError.new("invalid keyword at #{ptr}")
  36. end
  37. end
  38.  
  39. def json_parse_string(text, ptr = 0)
  40. abort "json_parse_string" if text[ptr] != '"'
  41. ptr += 1
  42. state = :string
  43. str = ""
  44. hex4 = ""
  45. while text[ptr]
  46. if state == :string
  47. if text[ptr] == '"'
  48. return [str, ptr+1]
  49. elsif text[ptr] == "\\"
  50. state = :escape
  51. ptr += 1
  52. else
  53. str << text[ptr]
  54. ptr += 1
  55. end
  56. elsif state == :escape
  57. if text[ptr] == '"'
  58. str << '"'; state = :string; ptr += 1
  59. elsif text[ptr] == "\\"
  60. str << "\\"; state = :string; ptr += 1
  61. elsif text[ptr] == "/"
  62. str << "/"; state = :string; ptr += 1
  63. elsif text[ptr] == "b"
  64. str << "\b"; state = :string; ptr += 1
  65. elsif text[ptr] == "f"
  66. str << "\f"; state = :string; ptr += 1
  67. elsif text[ptr] == "n"
  68. str << "\n"; state = :string; ptr += 1
  69. elsif text[ptr] == "r"
  70. str << "\r"; state = :string; ptr += 1
  71. elsif text[ptr] == "t"
  72. str << "\t"; state = :string; ptr += 1
  73. elsif text[ptr] == "u"
  74. hex4 = ""; state = :hexadec; ptr += 1
  75. end
  76. elsif state == :hexadec
  77. hex4 << text[ptr]
  78. if hex4.size == 4
  79. str << [hex4.to_i(16)].pack("U")
  80. state = :string
  81. end
  82. ptr += 1
  83. end
  84. end
  85. raise MyJSONError.new("invalid 4 hexadecimal digits at #{ptr}") if state == :hexadec
  86. raise MyJSONError.new("not found '\"' at #{ptr}")
  87. # メモ:シングルクオートはエスケープしないが,
  88. # エディタがエスケープするので'\'ではなく"\\"に...
  89. end
  90.  
  91. def json_parse_number(text, ptr = 0)
  92. sgn = 1
  93. val = 0
  94. if text[ptr] == '-'
  95. sgn = -1
  96. ptr += 1
  97. end
  98. while is_digit_char(text, ptr)
  99. val = val*10 + text[ptr].to_i
  100. ptr += 1
  101. end
  102. return [sgn*val, ptr]
  103. end
  104.  
  105. def json_parse_array(text, ptr = 0)
  106. abort "json_parse_array" if text[ptr] != '['
  107. ptr += 1
  108. arr = []
  109. state = :initial
  110. while text[ptr]
  111. if is_space_char(text, ptr)
  112. ptr += 1
  113. elsif text[ptr] == ']'
  114. raise MyJSONError.new("invalid ',' at #{ptr}") if state != :initial && state != :value
  115. return [arr, ptr+1]
  116. elsif text[ptr] == ','
  117. raise MyJSONError.new("invalid ',' at #{ptr}") if state != :value
  118. state = :comma
  119. ptr += 1
  120. else
  121. v, ptr = json_parse(text, ptr)
  122. arr << v
  123. state = :value
  124. end
  125. end
  126. raise MyJSONError.new("not found ']' at #{ptr}")
  127. end
  128.  
  129. def json_parse_object(text, ptr = 0)
  130. abort "json_parse_object" if text[ptr] != '{'
  131. ptr += 1
  132. hash = {}
  133. key = nil
  134. state = :initial
  135. while text[ptr]
  136. if is_space_char(text, ptr)
  137. ptr += 1
  138. elsif text[ptr] == '}'
  139. raise MyJSONError.new("invalid ',' at #{ptr}") if state != :initial && state != :value
  140. return [hash, ptr+1]
  141. elsif text[ptr] == ','
  142. raise MyJSONError.new("invalid ',' at #{ptr}") if state != :value
  143. state = :comma
  144. ptr += 1
  145. elsif text[ptr] == ':'
  146. raise MyJSONError.new("invalid ':' at #{ptr}") if state != :key
  147. state = :colon
  148. ptr += 1
  149. elsif text[ptr] == '"' && (state == :comma || state == :initial)
  150. key, ptr = json_parse(text, ptr)
  151. state = :key
  152. else
  153. val, ptr = json_parse(text, ptr)
  154. hash[key] = val
  155. state = :value
  156. end
  157. end
  158. raise MyJSONError.new("not found '}' at #{ptr}")
  159. end
  160.  
  161. def json_parse(text, ptr = 0)
  162. while text[ptr]
  163. if is_space_char(text, ptr)
  164. ptr += 1
  165. elsif text[ptr] == 't'
  166. return json_parse_true(text, ptr)
  167. elsif text[ptr] == 'f'
  168. return json_parse_false(text, ptr)
  169. elsif text[ptr] == 'n'
  170. return json_parse_null(text, ptr)
  171. elsif text[ptr] == '"'
  172. return json_parse_string(text, ptr)
  173. elsif text[ptr] == '-'
  174. return json_parse_number(text, ptr)
  175. elsif is_digit_char(text, ptr)
  176. return json_parse_number(text, ptr)
  177. elsif text[ptr] == '['
  178. return json_parse_array(text, ptr)
  179. elsif text[ptr] == '{'
  180. return json_parse_object(text, ptr)
  181. else
  182. raise MyJSONError.new("invalid at #{ptr}")
  183. end
  184. end
  185. end
  186.  
  187.  
  188.  
  189. # - - - - - - - - - - -
  190.  
  191. def test_sub
  192. abort "is_space_char" unless is_space_char(" ") == true
  193. abort "is_space_char" unless is_space_char("t") == false
  194. end
  195. test_sub
  196.  
  197. def test_main
  198. abort "failed: true" unless json_parse('true')[0] == true
  199. abort "failed: false" unless json_parse('false')[0] == false
  200. abort "failed: null" unless json_parse('null')[0] == nil
  201. abort "failed: string" unless json_parse('"str"')[0] == 'str'
  202. abort "failed: escape" unless json_parse('"foo\nbar"')[0] == "foo\nbar"
  203. abort "failed: hexadecimal" unless json_parse('"\u7D05\u7389"')[0] == "紅玉"
  204. abort "failed: number" unless json_parse('1234567890')[0] == 1234567890
  205. abort "failed: negative number" unless json_parse('-1')[0] == -1
  206. abort "failed: array 1" unless json_parse('[1,2,3]')[0] == [1,2,3]
  207. abort "failed: array 2" unless json_parse('[1,"foo",null]')[0] == [1,'foo',nil]
  208. abort "failed: matrix" unless json_parse('[[1,2],[3,4],[5,6]]')[0] == [[1,2],[3,4],[5,6]]
  209. abort "failed: russian array" unless json_parse('[0,[1,[2,[3,[4]]]]]')[0] == [0,[1,[2,[3,[4]]]]]
  210. abort "failed: object 1" unless json_parse('{"key":"val"}')[0] == {"key"=>"val"}
  211. abort "failed: object 2" unless json_parse('{"a":null,"b":[1,2],"c":true,"d":{"x":"\t"}}')[0] == {"a"=>nil,"b"=>[1,2],"c"=>true,"d"=>{"x"=>"\t"}}
  212. end
  213. test_main
Success #stdin #stdout 0.01s 5936KB
stdin
Standard input is empty
stdout
Standard output is empty