Ruby 如何将 Json 转换成 Hash?

robertyu · 2013年01月07日 · 最后由 Saito 回复于 2013年01月07日 · 6841 次阅读

{ "name": "name", "id": 12112, "sex": "male", "birthday": "2012-09-08" }

转换成

{ “name” => "name", "id" => 12112, "sex" =>"male", "birthday" => "2012-09-08" }

有没有 gem,或者方法?

[1] pry(main)> require'json'
=> true
[2] pry(main)> JSON.parse("{\"val\":\"test\",\"val1\":\"test1\",\"val2\":\"test2\"}")
=> {"val"=>"test", "val1"=>"test1", "val2"=>"test2"}
[3] pry(main)> '''
[3] pry(main)* {
[3] pry(main)* "name": "name",
[3] pry(main)* "id": 12112,
[3] pry(main)* "sex": "male",
[3] pry(main)* "birthday": "2012-09-08"
[3] pry(main)* }
[3] pry(main)* '''
=> "\n{\n\"name\": \"name\",\n\"id\": 12112,\n\"sex\": \"male\",\n\"birthday\": \"2012-09-08\"\n}\n"
[4] pry(main)> x = _
=> "\n{\n\"name\": \"name\",\n\"id\": 12112,\n\"sex\": \"male\",\n\"birthday\": \"2012-09-08\"\n}\n"
[5] pry(main)> JSON.parse(x)
=> {"name"=>"name", "id"=>12112, "sex"=>"male", "birthday"=>"2012-09-08"}

#1 楼 @Saito ''' 其实是 '' + ' ...

#2 楼 @luikore 好吧,语法都忘了... 果然是 Clojure 看多了。

为什么我总有 ''' 有点什么的既视感。

' => Char " => String ''' => String W/O escape

其实这样挺好的。

#4 楼 @Saito 其实 char 的唯一作用就是当整数用,既然有整数类型了要 char 有何用...

Char 还是有点用的,Ruby 的 String 不是 Enumerable 的,也没有 Char. 所以很多好使的方法都用不了。( Ruby String 没有内部编码。间接导致实现了个 each_byte each_char. each_char 出来的还都是 String, 这才是略坑爹的地方。

Clojure:

user=> (seq "abc")
(\a \b \c)
user=> (first "abc")
\a
user=> (last "abc")
\c
user=> (cycle "abc")
(\a \b \c \a \b \c \a \b \c \a ...)
user=> (take 2 "abc")
(\a \b)
user=> (every? char? "abcdefg")
true

Ruby:

[1] pry(main)> "123"
=> "123"
[2] pry(main)> "123".first
NoMethodError: undefined method `first' for "123":String
from (pry):3:in `__pry__'
[3] pry(main)> "123".last
NoMethodError: undefined method `last' for "123":String
from (pry):4:in `__pry__'
[4] pry(main)> "123".map
NoMethodError: undefined method `map' for "123":String
from (pry):6:in `__pry__'
[5] pry(main)> "123".each
NoMethodError: undefined method `each' for "123":String
from (pry):8:in `__pry__'
[6] pry(main)> "123".each_char
=> #<Enumerator: ...>
[7] pry(main)> "123".each_char{|c| p c.class}
String
String
String
=> "123"

如果 Ruby 有 Char, 直接 Mixin Enumerable 就好了。该有的都有了..

#1 楼 @Saito
pry(main)> ''' [3] pry(main)* { [3] pry(main)* "name": "name", [3] pry(main)* "id": 12112, [3] pry(main)* "sex": "male", [3] pry(main)* "birthday": "2012-09-08" [3] pry(main)* } [3] pry(main)* ''' 怎么得到下面的结果呢? "\n{\n\"name\": \"name\",\n\"id\": 12112,\n\"sex\": \"male\",\n\"birthday\": \"2012-09-08\"\n}\n"

我怎么都不好使呢?

#6 楼 @Saito

char 类型问题可多了... 首先字符串必须内码一致并且用定长编码,如果处理是不同编码的内容,就要先统一转换成内码再处理,你是可以直接用 enumerable 方法,但是之前和之后的转换比 each_char / each_byte 要麻烦,而且用户又怎么知道迭代的是字符还是字节呢?

内码其实用 utf-32 才是正确的,但由于历史原因 (最初他们以为全宇宙字符不会超过 65535 个), 常见语言都用了 utf-16 (最初定长的时候叫 ucs-2), 例如 C++ 的 wchar_t (wchar_t 在各平台长度不一样又是另一个坑了...), OC 的 uchar, Java 的 char.

但 utf-16 和 utf-32 都有 less endian 和 big endian 的不同 (例如 windows 的 "unicode" 和 java 的 "unicode" 是二进制不兼容的)...

超过 65535 的字符要两个 char 才能表示,为了解决这个问题,就衍生出各种新概念 (如 glyph) 去表达原本"字符"的意思,定长编码的预设也失效了,char 类型也不是字符的意思了,可坑爹了...

ruby 处理 utf-8 字符串:

"𝄞".size #=> 1
"𝄞".bytesize #=> 4

java 里:

String s = "𝄞";
s.length(); //=> 2 WTF?
s.codePointCount(0, s.length()); //=> 要得到正确的结果, 还要在 javac 加上 -encoding UTF-8 参数

所有基于 java 的二奶语言弄这类超出 65535 的字符都超蛋疼 (jruby 虽然结果正确,但 irb 输入都困难...) clojure 我整了个 rlwrap 可以输入了但正确结果我是弄不出来 ...

归根结底最大的祸害就是这个暧昧不清的 char 类型...

#7 楼 @robertyu 那是在 pry 输入的,代码中这么写不行?

require 'json'
JSON.parse '{
"name": "name",
"id": 12112,
"sex": "male",
"birthday": "2012-09-08"
}'
(def wtf "𝄞")
(println (.length wtf))
(println (.codePointCount wtf 0 (.length wtf)))

好吧,跟编码扯上关系就没完了..

内码一致 还是 没有内码 各有各的好处。

#10 楼 @Saito 内码是 utf32 的话没问题的,但内码残废没有好处...

(println (seq "123𝄞"))
#=> (1 2 3 ? ?)

这个确实是错的。orz...

统一内码 UTF-8 就没啥问题了。只是性能要下降.. Java 的这个内码选择可能在当时已经是最优的了..

没记错的话,Matz 的书上说:Java 生早了..

miao 为什么 Ruby 里的 String 没有 include Enumerable ? 提及了此话题。 03月03日 14:48
需要 登录 后方可回复, 如果你还没有账号请 注册新账号