【问题标题】:Parsing non-curly braced unicode emoji in Ruby在 Ruby 中解析非花括号 unicode 表情符号
【发布时间】:2017-08-24 17:57:51
【问题描述】:

我从无法控制的 API 接收到一些文本。当我收到表情符号时,它们没有为 Ruby 正确编码。这是我收到的一个示例:

  • 编码:“\u1F44C”
  • 解码:“ὄC”

Ruby 不处理超过 4 个十六进制字符的 unicode,除非您使用花括号。所以“\u{1F44C}”会被正确解码为????。

如何将 API 的输出转换为 Ruby 可以正确解码的格式?

【问题讨论】:

  • 在 Ruby 接触它之前,实际的 API 响应是什么样的(例如来自 curl)?它的编码是什么?你得到例如在 UTF-8 中表示 ???? 的四个字节(0xF0 0x9F 0x91 0x8C),或者你得到的是文字字符\ u1,...(这将是 7 个字节)?
  • @Jordan 我刚刚在浏览器中发出了一个 API 请求并收到了这个 JSON 有效负载:{ "text": "OK\u1F44C let me see." } 响应标头是:Content-Type:application/json; charset=UTF-8
  • 那么在响应中\u1F44C\ u1 等7 个字节?
  • @Jordan \u1F44C 是我正在查看的 7 个字节。
  • 您在这里处理的是一个损坏的 API。这不是 Ruby 问题,而是 JSON 编码器问题。根据the JSON spec,“要转义不在基本多语言平面中的扩展字符 [即 U+0000 到 U+FFFF],该字符表示为 12 个字符序列,编码 UTF-16 代理对。” ???? 的正确编码是 \uD83D\uDC4C。任何兼容的 JSON 解析器都会产生与您看到的相同的输出。您应该向 API 供应商报告错误。

标签: json ruby unicode emoji


【解决方案1】:

您在这里处理的是一个损坏的 API。这不是 Ruby 问题,而是 JSON 编码器问题。每the JSON spec

如果字符在基本多语言平面(U+0000 到 U+FFFF),那么它可以表示为六个字符的序列:一个反斜线,后跟小写字母 u,后跟四个编码字符代码点的十六进制数字。十六进制字母A 虽然F 可以是大写或小写。因此,例如,一个只包含一个反斜线字符的字符串可以表示为“\u005C”。

...

要转义不在基本多语言平面中的扩展字符,该字符表示为 12 字符序列,编码 UTF-16 代理对。因此,例如,仅包含 G 谱号字符 (U+1D11E) 的字符串可以表示为“\uD834\uDD1E”。

所以? 的正确编码是\uD83D\uDC4C。任何兼容的 JSON 解析器都会产生与您看到的相同的输出。您应该向 API 供应商报告错误——您几乎肯定不是他们唯一遇到此问题的客户。

如果您无法让 API 供应商修复他们的 API,除了实现自己的 JSON 解析器(或放弃供应商)之外,您唯一的办法就是尝试使用正则表达式修复 JSON 响应。类似这样的方法可行,但 容易受到误报的影响,这意味着一些有效的 JSON 会被破坏:

require "json"

def mangle_json(str)
  str.gsub(/\\u([0-9a-f]{5,6})/i) do
    begin
      $1.to_i(16).chr(Encoding::UTF_8)
    rescue RangeError
      $&
    end
  end
end

bad_json = '{"text":"OK\u1F44C let me see."}'

puts JSON.parse(bad_json)["text"]
# => OKὄC let me see.

puts JSON.parse(mangle_json(bad_json))["text"]
# => OK? let me see.

在 repl.it 上查看:https://repl.it/GnFp/1

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-12-22
    • 1970-01-01
    • 2019-01-26
    • 1970-01-01
    • 1970-01-01
    • 2021-11-04
    • 2016-07-17
    • 1970-01-01
    相关资源
    最近更新 更多