在Ruby中解析非花括号的unicode表情符号

时间:2017-03-30 17:03:21

标签: json ruby unicode emoji

我收到了一些我无法控制的API文字。当我收到表情符号时,他们没有正确编码Ruby。这是我收到的一个例子:

  • 编码:" \ u1F44C"
  • 解码:"ὄC"
除非你使用大括号,否则Ruby不会处理超过4个十六进制字符的unicode。所以" \ u {1F44C}"将正确解码为。

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

1 个答案:

答案 0 :(得分:4)

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

  

如果角色在基本多语言平面(U + 0000到U + FFFF)中,那么它可以表示为六个字符的序列:反向固相,后跟小写字母u,然后由四个十六进制数字编码字符的代码点。尽管A,但十六进制字母F可以是大写或小写。因此,例如,仅包含单个反向固相字符的字符串可以表示为" \u005C"。

     

...

     

要转义不在Basic Multilingual Plane中的扩展字符,该字符将表示为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