您现在的位置是:群英 > 开发技术 > web开发
Ruby处理YAML和json的方法,用什么方法处理更精准
Admin发表于 2022-05-26 17:28:30937 次浏览
这篇文章主要给大家介绍“Ruby处理YAML和json的方法,用什么方法处理更精准”的相关知识,下文通过实际案例向大家展示操作过程,内容简单清晰,易于学习,有这方面学习需要的朋友可以参考,希望这篇“Ruby处理YAML和json的方法,用什么方法处理更精准”文章能对大家有所帮助。

ruby处理yaml

ruby的标准库yaml基于psych:https://ruby-doc.org/stdlib-2.6.2/libdoc/psych/rdoc/psych.html

require 'yaml' 之后,为大多数的基本数据类型都提供了 to_ yaml() 方法,用于将各数据类型的对象转换为yaml格式。

例如:

require 'yaml'
require 'set'

p "hello world".to_yaml
p 123.to_yaml
p %w(perl shell php).to_yaml
p ({one: 1, two: 2}).to_yaml
p set.new([1,2,3]).to_yaml

得到:

"--- hello world\n"
"--- 123\n"
"---\n- perl\n- shell\n- php\n"
"---\n:one: 1\n:two: 2\n"
"--- !ruby/object:set\nhash:\n  1: true\n  2: true\n  3: true\n"

也可以使用yaml.dump()方法实现和to_yaml相同的功能,它还可以写入文件。

users = [{name: 'bob', permissions: ['read']},
 {name: 'alice', permissions:['read', 'write']}]

file.open("/tmp/a.yml","w") { |f| yaml.dump(users, f) }

查看文件:

---
- :name: bob             #=> 注意,保留了hash源数据中的符号
  :permissions:
  - read
- :name: alice
  :permissions:
  - read
  - write

用yaml.load()从yaml中读取数据:

require 'yaml'

pp yaml.load(data)

__end__
mysql:
  passwd: p@ssword1!
  user: root
  port: 3306
  other1: nil
  other2: false
  other3: ""
  hosts: 
    - ip: 10.10.1.1
      hostname: node1
    - ip: 10.10.1.2
      hostname: node2

得到:

{"mysql"=>
  {"passwd"=>"p@ssword1!",      #=> 注意,key是string而非symbol
   "user"=>"root",
   "port"=>3306,
   "other1"=>"nil",
   "other2"=>false,
   "other3"=>"",
   "hosts"=>
    [{"ip"=>"10.10.1.1", "hostname"=>"node1"},
     {"ip"=>"10.10.1.2", "hostname"=>"node2"}]}}

如果想让hash的key是符号而非字符串,可以设置选项symbolize_names: true

pp yaml.load(data, symbolize_names: true)

需要注意,yaml可以将对象进行序列化,所以有几方面注意事项:

  • 在反序列化的时候需要也require涉及到的文件,例如对set类型序列化后,在反序列化时如不require 'set'则无法还原对象
  • 有些底层对象不能序列化,包括io流、ruby代码对象proc、binding等
  • 不要反序列化不被信任的数据对象(比如用户输入的数据),此时可使用safe_load(),它默认只允许加载以下几种类型的数据:
    • trueclass
    • falseclass
    • nilclass
    • numeric
    • string
    • array
    • hash
  • 如果确实想要加载额外的数据类型,可以在safe_load()中指定参数permitted_classes: []或permitted_symbols: []

ruby处理json数据

转为json格式字符串

使用json.generate()可以将对象或数组转换为json格式的数据:

require 'json'
p json.generate "abc"
p json.generate 123
p json.generate true
p json.generate nil
p json.generate [2,3,4]
p json.generate({name: "junmajinlong", age: 23})
require 'set'
p json.generate(set.new([1,23,44]))

得到:

"\"abc\""
"123"
"true"
"null"
"[2,3,4]"
"{\"name\":\"junmajinlong\",\"age\":23}"
"\"#<set: {1, 23, 44}>\""

require 'json'后,很多ruby类型都具备了一个to_json的方法,可以直接将该类型的数据转换为json数据:

p ({name: "junmajinlong", age: 23}).to_json
p (set.new([1,23,44])).to_json

得到:

"{\"name\":\"junmajinlong\",\"age\":23}"
"\"#<set: {1, 23, 44}>\""

此外,json.dump()也可以将对象转换为json格式的字符串,而且它还支持写入文件:

hsh = {name: "junmajinlong", age: 23}
file.open("/tmp/a.json", "w") {|f| json.dump(hsh, f)}

json格式字符串转为ruby对象

要从json格式字符串转为ruby对象,有一些选项可设置,参考https://ruby-doc.org/stdlib-2.7.1/libdoc/json/rdoc/json.html#method-i-parse,比如*symbolize_names*选项表示是否将json object中的key解析为符号类型的key,如果设置为false,则解析为字符串的key。

要将json格式的字符串解析为ruby数据类型(hash),使用json.parse()

require 'json'

hsh = '{"name": "junmajinlong", "age": 23}'

p json.parse(hsh)
p json.parse(hsh, symbolize_names: true)

注意,上面的json字符串必须是合理的json数据,比如key必须使用双引号包围而不能使用单引号,字符串必须使用双引号包围,等等。比如"{'name': 'junmajinlong', 'age': 23}"就不是合理的json字符串。

要从json文件中读取json数据并转换为ruby数据,使用load():

data = file.open("/tmp/a.json") do |f|
  json.load(f)
end

pp data
#=> {"name"=>"junmajinlong", "age"=>23}

自定义对象的转换方式

json支持的数据类型有:

  • 字符串
  • 数值
  • 对象
  • 数组
  • 布尔
  • null

从一种语言的数据转换为json数据时,如果数据类型也是json所支持的,可直接转换,但如果包含了json不支持的类型,则可能报错,也可能以一种对象字符串的方式保存,这取决于对应的实现。

可以在对象中定义as_json实例方法来决定对象如何转换为json字符串,再定义类方法from_json()来决定如何从json字符串中恢复为一个对象。

例如,

require 'json'
require 'date'

class person
  attr_accessor :name, :birthday
  def initialize name, birthday
    @name = name
    @birthday = datetime.parse(birthday)
  end
end

file.open("/tmp/p.json", "w") do |f|
  json.dump(person.new("junmajinlong", "1999-10-11"), f)
end

查看保存的json数据:

$ cat /tmp/p.json
"#<person:0x00007fffc7e575d0>"

定义as_jsonfrmo_json

require 'json'
require 'date'

class person
  attr_accessor :name, :birthday
  
  def initialize name, birthday
    @name = name
    @birthday = datetime.parse(birthday)
  end
  
  def as_json
    {
      name: @name,
      birthday: @birthday.strftime("%f")
    }
  end

  def self.from_json json
    data = json.parse(json)
    new(data["name"], data["birthday"])
  end
end

之后要序列化、反序列化该对象,可:

data = person.new("junmajinlong", "1999-10-11").as_json
p data

p1=person.from_json(json.dump data)
p p1.birthday

如果是读写json文件,可:

person1 = person.new("junmajinlong", "1999-10-11")
file.open("/tmp/p.json", "w") do |f|
  json.dump(person1.as_json, f)
end

p1 = file.open("/tmp/p.json") do |f|
  person.from_json(f.read)
  # person.from_json(json.load(f).to_json)
end
p p1

几种json解析工具的性能测试

测试了json标准库、oj和fast_josnparser解析json的性能,测试项包括:

  • 从文件中加载并解析json字符串为ruby对象
  • 从内存json字符串中解析json字符串为ruby对象
  • 带有symbolize_keys/symbolize_names转换时的解析
  • json标准库和oj将ruby对象dump为json字符串
  • json标准库和oj将ruby对象dump为json字符串保存到文件

注:

  • fast_jsonparser没有dump功能,只有解析json字符串功能
  • oj在将对象转换为json字符串时,可能会丢失数据的精度,比如浮点数的精度

测试的json字符串数量大约50m。

测试了ruby 2.7.1和ruby 3.0.1两个版本,gem包的版本信息如下:

fast_jsonparser (0.5.0)
json (default: 2.5.1)
oj (3.11.7)

测试代码:

require 'benchmark'
require 'json'
require 'oj'
require 'fast_jsonparser'

# warm
json_file='test'  # 文件大小大约50m
str = file.read(json_file)

######## json

puts " load file ".center(80, '-')
benchmark.bm(30) do |x|
  x.report("json.load:") { file.open(json_file){ |f| json.load(f) } }
  x.report("oj.load_file:") { oj.load_file(json_file) }
  x.report("fastjsonparser.load:") { fastjsonparser.load(json_file) }
end

puts
puts " load file with symbolize_keys ".center(80, '-')
benchmark.bm(30) do |x|
  x.report("json.load:") { file.open(json_file){ |f| json.load(f, nil, symbolize_names: true, create_additions: false) } }
  x.report("oj.load_file:") { oj.load_file(json_file, symbol_keys: true) }
  x.report("fastjsonparser.load:") { fastjsonparser.load(json_file, symbolize_keys: true) }
end

puts
puts " parse str ".center(80, '-')
benchmark.bm(30) do |x|
  x.report("json.parse:") { json.parse(str) }
  x.report("oj.load:") { oj.load(str) }
  x.report("fastjsonparser.parse:") { fastjsonparser.parse(str) }
end

puts
puts " parse str with symbolize_keys ".center(80, '-')
benchmark.bm(30) do |x|
  x.report("json.parse:") { json.parse(str, symbolize_names: true) }
  x.report("oj.load:") { oj.load(str, symbol_keys: true) }
  x.report("fastjsonparser.parse:") { fastjsonparser.parse(str, symbolize_keys: true) }
end

obj = json.parse(str, symbolize_names: true)

puts 
puts " dump json to str ".center(80, '-')
benchmark.bm(30) do |x|
  x.report("json.dump:") { json.dump(obj) }
  x.report("oj.dump:") { oj.dump(obj) }
end

puts 
puts " dump json to file ".center(80, '-')
benchmark.bm(30) do |x|
  x.report("json.dump:") { file.open('0_json_dump', 'w') {|f| json.dump(obj, f) } }
  x.report("oj.to_file:") { oj.to_file('0_oj_dump', obj) }
end

测试结果:

ruby 2.7.1中:

---------------------------------- load file -----------------------------------
                                     user     system      total        real
json.load:                       1.591831   0.058021   1.649852 (  1.738119)
oj.load_file:                    1.350385   0.057684   1.408069 (  2.434268) <-慢
fastjsonparser.load:             0.653968   0.103258   0.757226 (  0.848913) <-快

------------------------ load file with symbolize_keys -------------------------
                                     user     system      total        real
json.load:                       1.212617   0.039052   1.251669 (  1.349545)
oj.load_file:                    1.432059   0.098950   1.531009 (  2.679610) <-慢
fastjsonparser.load:             0.695538   0.008384   0.703922 (  0.797081) <-快

---------------------------------- parse str -----------------------------------
                                     user     system      total        real
json.parse:                      1.343596   0.000000   1.343596 (  1.350368)
oj.load:                         1.133612   0.000000   1.133612 (  1.140939)
fastjsonparser.parse:            0.701701   0.012340   0.714041 (  0.720296) <-快

------------------------ parse str with symbolize_keys -------------------------
                                     user     system      total        real
json.parse:                      1.250775   0.000000   1.250775 (  1.258796)
oj.load:                         1.131296   0.000000   1.131296 (  1.138020)
fastjsonparser.parse:            0.697433   0.015962   0.713395 (  0.719439) <-快

------------------------------- dump json to str -------------------------------
                                     user     system      total        real
json.dump:                       1.374611   0.028454   1.403065 (  1.403081)
oj.dump:                         1.025049   0.040184   1.065233 (  1.065246) <-快

------------------------------ dump json to file -------------------------------
                                     user     system      total        real
json.dump:                       1.234362   0.040246   1.274608 (  1.369214)
oj.to_file:                      1.168707   0.000000   1.168707 (  1.270957)

ruby 3.0.1中:

---------------------------------- load file -----------------------------------
                                     user     system      total        real
json.load:                       1.362151   0.083610   1.445761 (  1.569754)
oj.load_file:                    1.343601   0.182046   1.525647 (  2.684472) <-慢
fastjsonparser.load:             2.634435   0.052734   2.687169 (  2.776105) <-慢

------------------------ load file with symbolize_keys -------------------------
                                     user     system      total        real
json.load:                       1.287954   0.018572   1.306526 (  1.409770)
oj.load_file:                    1.478750   0.043847   1.522597 (  2.668882) <-慢
fastjsonparser.load:             2.717857   0.006164   2.724021 (  2.822728) <-慢

---------------------------------- parse str -----------------------------------
                                     user     system      total        real
json.parse:                      1.242225   0.008661   1.250886 (  1.304554)
oj.load:                         1.097922   0.000000   1.097922 (  1.110031)
fastjsonparser.parse:            2.602679   0.017232   2.619911 (  2.634604) <-慢

------------------------ parse str with symbolize_keys -------------------------
                                     user     system      total        real
json.parse:                      1.368262   0.000000   1.368262 (  1.380730)
oj.load:                         1.332349   0.000000   1.332349 (  1.346331)
fastjsonparser.parse:            2.706804   0.007238   2.714042 (  2.726935) <-慢

------------------------------- dump json to str -------------------------------
                                     user     system      total        real
json.dump:                       1.724653   0.009250   1.733903 (  1.733912)
oj.dump:                         1.298235   0.030041   1.328276 (  1.328279) <-快

------------------------------ dump json to file -------------------------------
                                     user     system      total        real
json.dump:                       1.765664   0.040595   1.806259 (  1.905785)
oj.to_file:                      1.228744   0.020309   1.249053 (  1.349684) <-快
=end

性能测试结论:

  • (1).ruby 3之前,fast_jsonparser非常快,但是ruby 3中的fast_jsonparser很慢
  • (2).oj解析本地json字符串的性能比标准库json性能稍好,但oj从文件中加载并解析json的速度很慢
  • (3).oj将ruby对象解析为json字符串的效率比json标准库性能好

即:

dump:
oj.dump > json.dump

ruby3 之前:
fastjsonparser.load > json.load > oj.load_file
fastjsonparser.parse > oj.load > json.parse

ruby3 之后:
json.load > oj.load_file > fastjsonparser.load
oj.load > json.parse > fastjsonparser.parse

multi_json

有一个名为multi_json的gem包,它提供多种json包的功能,默认采用oj作为json的适配引擎。它支持下面几种json适配器:

  • oj optimized json by peter ohler
  • yajl yet another json library by brian lopez
  • json the default json gem with c-extensions (ships with ruby 1.9+)
  • json pure a ruby variant of the json gem
  • nsjsonserialization wrapper for apple’s nsjsonserialization in the cocoa framework (macruby only)
  • gson.rb a ruby wrapper for google-gson library (jruby only)
  • jrjackson jruby wrapper for jackson (jruby only)
  • okjson a simple, vendorable json parser

如果oj已被require,则默认采用oj处理json,如果oj没有被require,而是require了yajl,则采用yajl处理json,依次类推。

它提供了load()和dump()方法:

load(json_str, options = {})
  options: 
    symbolize_keys: true, false
    adapter:  oj, json_gem, yajl, json_pure, ok_json

dump(object, options = {})

感谢各位的阅读,以上就是“Ruby处理YAML和json的方法,用什么方法处理更精准”的内容了,通过以上内容的阐述,相信大家对Ruby处理YAML和json的方法,用什么方法处理更精准已经有了进一步的了解,如果想要了解更多相关的内容,欢迎关注群英网络,群英网络将为大家推送更多相关知识点的文章。

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:mmqy2019@163.com进行举报,并提供相关证据,查实之后,将立刻删除涉嫌侵权内容。

相关信息推荐
2022-10-08 17:52:19 
摘要:PHPSpreadsheet导出Excel列数超过26报错怎么办?下面本篇文章给大家介绍一下PhpSpreadsheet导出Excel超过26列解决办法,希望对大家有帮助。
2021-10-29 18:00:09 
摘要:这篇文章给大家分享的是PHP如何屏蔽错误的内容,一些朋友可能对于PHP如何屏蔽错误不是很了解,对此本文介绍了四种PHP屏蔽错误的方法,感兴趣的朋友接下来一起跟随小编来了解看看吧。
2022-06-16 09:25:42 
摘要:方法:1、用“$sum=0;”定义一个变量,用于存储计算结果;2、用“foreach($arr as $v){}”循环遍历数组;3、在循环体中,检查数组元素是否为奇数,如果是则相加起来,语法“if($v%2!=0){$sum+=$v;}”。
云活动
推荐内容
热门关键词
热门信息
群英网络助力开启安全的云计算之旅
立即注册,领取新人大礼包
  • 联系我们
  • 24小时售后:4006784567
  • 24小时TEL :0668-2555666
  • 售前咨询TEL:400-678-4567

  • 官方微信

    官方微信
Copyright  ©  QY  Network  Company  Ltd. All  Rights  Reserved. 2003-2019  群英网络  版权所有   茂名市群英网络有限公司
增值电信经营许可证 : B1.B2-20140078   粤ICP备09006778号
免费拨打  400-678-4567
免费拨打  400-678-4567 免费拨打 400-678-4567 或 0668-2555555
微信公众号
返回顶部
返回顶部 返回顶部