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

Handling bad UTF-8 from json,in ruby

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

1
2
3
4
5
6
7
8
9
10
{
"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拉下来的方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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/glebpoov/hacker-news-droid-api/issues/4


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

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

在Ruby1.9.3中,如果您知道编码应该是什么,就可以强制进行编码。试试这个:

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

JSON解析器应该按照您想要的方式处理UTF-8。

工具书类

  • http://bugs.ruby-lang.org/-net::http无法正确处理编码

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

Net::HTTP有点乱。

1.9:

  • 如果服务器发送一个分块的响应,您将始终得到ASCII-8bit。这似乎优先于其他方案。
  • 如果使用Get对象调用http.request,则会得到us-ascii。此方法不为您进行压缩。
  • 如果调用http.get,则启用压缩。
    • 如果服务器支持压缩,您将得到ASCII-8bit
    • 如果服务器不发送压缩体,您将得到us-ascii

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

解压产生ASCII-8bit,因为在解压时,它在Get方法中进行了硬编码。

在2.0中,似乎总是返回UTF-8,但这是因为这是默认的源文件编码。如果您通过-K选项更改它,响应编码将相应地更改。试着把nesu传给-K