我一直在四处寻找,我认为问题出在谷歌的尽头。
接收到的数据是 Ruby 中的哈希,或 JavaScript 中的对象,并且根据规范,键应该被引用,因为它们是字符串。一个对象被包装在{
and}
中,"string": value
格式为。字符串要用双引号括起来:"string"
.
通过对接收到的数据进行预处理,将键名转换为带引号的键名,可以解析 JSON:
require 'open-uri'
require 'json'
FIELDS = %w[lhs rhs error icc]
%w[COP USD AED YER ZAR ZMK].each do |currency|
data = open('http://www.google.com/ig/calculator?hl=en&q=1USD=?' + currency).read
FIELDS.each { |f| data.sub!(f, %Q["#{f}"]) }
puts JSON[data]
end
运行后,这些是通过解析 JSON 创建的哈希:
{"lhs"=>"1 U.S. dollar", "rhs"=>"1 890.35917 Colombian pesos", "error"=>"", "icc"=>true}
{"lhs"=>"1 U.S. dollar", "rhs"=>"1 U.S. dollar", "error"=>"0", "icc"=>true}
{"lhs"=>"1 U.S. dollar", "rhs"=>"3.67290571 United Arab Emirates dirhams", "error"=>"", "icc"=>true}
{"lhs"=>"1 U.S. dollar", "rhs"=>"215.053763 Yemeni rials", "error"=>"", "icc"=>true}
{"lhs"=>"1 U.S. dollar", "rhs"=>"9.97575891 South African rands", "error"=>"", "icc"=>true}
{"lhs"=>"1 U.S. dollar", "rhs"=>"5 208.33333 Zambia kwacha", "error"=>"", "icc"=>true}
但是等等,还有更多......
YAML 是 JSON 的超集,因此 YAML 解析器应该能够理解 JSON。将接收到的“JSON”扔到 YAML 解析器中会处理未加引号的键:
require 'open-uri'
require 'yaml'
%w[COP USD AED YER ZAR ZMK].each do |currency|
data = open('http://www.google.com/ig/calculator?hl=en&q=1USD=?' + currency).read
puts YAML.load(data)
end
有了这个输出:
{"lhs"=>"1 U.S. dollar", "rhs"=>"1 890.35917 Colombian pesos", "error"=>"", "icc"=>true}
{"lhs"=>"1 U.S. dollar", "rhs"=>"1 U.S. dollar", "error"=>"0", "icc"=>true}
{"lhs"=>"1 U.S. dollar", "rhs"=>"3.67290571 United Arab Emirates dirhams", "error"=>"", "icc"=>true}
{"lhs"=>"1 U.S. dollar", "rhs"=>"215.053763 Yemeni rials", "error"=>"", "icc"=>true}
{"lhs"=>"1 U.S. dollar", "rhs"=>"9.97575891 South African rands", "error"=>"", "icc"=>true}
{"lhs"=>"1 U.S. dollar", "rhs"=>"5 208.33333 Zambia kwacha", "error"=>"", "icc"=>true}
YAML 不坚持引用哈希键。对于那些不是明显数字的东西,它默认为字符串,这是我尝试 YAML 的线索。
所以,在我看来,谷歌做错了事。如果他们要输出 JSON,他们应该输出正常的、语法正确的 JSON。如果他们要输出 YAML,他们应该输出常规的 YAML,而不是数据的这种“半快”序列化。API 可能有一种强制方式,但它应该默认为解析的 JSON。
您可能想考虑改用https://openexchangerates.org/。他们的示例输出似乎是一种更理智的方法。