处理来自 JSON 的损坏的 UTF-8 数据,在 Ruby 中。

8
我正在从远程JSON中提取数据,网址是http://hndroidapi.appspot.com/news/format/json/page/?appid=test。我遇到的问题是,这个API似乎没有正确处理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


看起来你收到的 JSON 响应主体可能包含 HTML 安全符号。我一眼看过去没有看见任何坏字符,并且我看到响应的 Content-Type 标头设置为 application/json; charset=utf-8,这看起来是正确的。你是如何获取响应主体的?我建议尝试使用像 Dev HTTP Client 或 CURL 这样的浏览器工具检查响应,看看你的应用程序得到的是否与实际响应有所不同。如果有差异,那么你的代码可能处理不正确。 - fdsaas
谢谢。我在编辑中添加了我的代码。问题是它们是HTML安全符号。但是,它不应该是欧元符号和“tm”符号。它应该是一个撇号。 - hodgesmr
你可以使用 puts res.body 在控制台中查看确切的响应。你是否通过 result 对象看到了后面的奇怪符号? - fdsaas
我看到的不是奇怪的符号,而是它们的 HTML 安全版本。因此,在上面的示例中,我实际上看到的是 €™,而不是撇号。这在 res.body 和稍后的 result 对象中都是如此。我认为这是因为 API 没有正确地表示撇号。所以,我希望能够以某种方式进行补偿。 - hodgesmr
1
啊,WTF-8与HTML实体转义,我以前从未见过。我感同身受。 - Lars Haugseth
2个回答

5

看起来你收到的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。 参考资料

4
使用force_encoding似乎是最好的解决方案。在回应Kevin Dickerson的答案后,这里有一个解释怪异现象的方法。 Net::HTTP有点混乱。
在1.9.3中:
- 如果服务器发送分块响应,则始终会得到ASCII-8BIT。这似乎优先于其他情况。 - 如果您使用Get对象调用http.request,则会得到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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接