在红宝石中处理来自json的坏UTF-8

时间:2012-06-18 22:15:49

标签: ruby json encoding utf-8

我正在http://hndroidapi.appspot.com/news/format/json/page/?appid=test从远程json中提取数据。我遇到的问题是这个API似乎正在构建JSON而没有正确处理UTF-8编码(如果我在这里错了,请纠正我)。例如,现在传递的部分结果是

{
"title":"IPad - please don€™t ding while you and I are asleep  ",
"url":"http://modern-products.tumblr.com/post/25384729998/ipad-please-dont-ding-while-you-and-i-are-asleep",
"score":"10 points",
"user":"roee",
"comments":"18 comments",
"time":"1 hour ago",
"item_id":"4128497",
"description":"10 points by roee 1 hour ago  | 18 comments"
}

注意don€™t。而这并不是它窒息的唯一一种角色。鉴于我不控制API,我有什么办法可以将数据转换成干净的东西吗?

编辑:

以下是我如何提取JSON:

hn_url = "http://hndroidapi.appspot.com/news/format/json/page/?appid=test"
  url = URI.parse(hn_url)

  # Attempt to get the json
  req = Net::HTTP::Get.new(hn_url)
  req.add_field('User-Agent', 'Test')
  res = Net::HTTP.start(url.host, url.port) {|http| http.request(req) }
  response = res.body
  if response.nil?
    puts "Bad response when fetching HN json"
    return
  end

  # Attempt to parse the json
  result = JSON.parse(response)
  if result.nil?
    puts "Error parsing HN json"
    return
  end

编辑2:

刚刚找到了API的GitHub页面。看起来这是一个突出的问题。仍然不确定我是否可以从我的角度做任何变通办法: https://github.com/glebpopov/Hacker-News-Droid-API/issues/4

2 个答案:

答案 0 :(得分:4)

看起来您正在接收的JSON响应正文是以US-ASCII而不是UTF-8接收的,因为Net::HTTP故意不强制编码。

1.9.3p194 :044 > puts res.body.encoding
US-ASCII

在Ruby 1.9.3中,如果你知道它应该是什么,你可以强制编码。试试这个:

response = res.body.force_encoding('UTF-8')

然后,JSON解析器应该按照您希望的方式处理UTF-8。

<强>参考

答案 1 :(得分:2)

使用force_encoding似乎是最好的解决方案。 继凯文迪克森的答案之后,这里有一个奇怪的解释。

Net::HTTP有点乱。

在1.9.3

  • 如果服务器发送分块响应,您将始终获得ASCII-8BIT。这似乎优先于其他方案。
  • 如果您使用http.request对象调用Get,则会获得US-ASCII。此方法不会为您执行压缩。
  • 如果您致电http.get,则会启用压缩功能。
    • 如果服务器支持压缩,则会获得ASCII-8BIT
    • 如果服务器没有发送压缩主体,则会获得US-ASCII

你会得到US-ASCII,因为当Net::HTTP创建缓冲区字符串来接收响应时,它是在解释器的默认源文件编码中创建的,它是US-ASCII。 (net/源文件,顶部没有魔术编码注释,因此它们使用ruby的默认值。)

解压缩产生ASCII-8BIT,因为它在解压缩时用get方法进行硬编码。

在2.0 上,好像你总是得到UTF-8,但这是因为这是默认的源文件编码。如果您通过-K选项进行更改,则响应编码会相应更改。尝试将nesu传递给-K