【问题标题】:Encode string as \uXXXX将字符串编码为 \uXXXX
【发布时间】:2016-08-31 06:23:19
【问题描述】:

我正在尝试将代码从 python 移植到 ruby​​,但在将 UTF-8 字符串编码为 JSON 的函数之一中遇到了困难。

我已将代码精简到我认为是我的问题的地方。

我想让 ruby​​ 输出与 python 完全相同的输出。

python代码:

#!/usr/bin/env python
# encoding: utf-8

import json
import hashlib

text = "ÀÈG"
js = json.dumps( { 'data': text } )

print 'Python:'
print js
print hashlib.sha256(js).hexdigest()

红宝石代码:

#!/usr/bin/env ruby
require 'json'
require 'digest'

text = "ÀÈG"
obj = {'data': text}
# js = obj.to_json # not using this, in order to get the space below
js = %Q[{"data": "#{text}"}]

puts 'Ruby:'
puts js
puts Digest::SHA256.hexdigest js

当我同时运行时,这是输出:

$ ./test.rb && ./test.py
Ruby:
{"data": "ÀÈG"}
6cbe518180308038557d28ecbd53af66681afc59aacfbd23198397d22669170e
Python:
{"data": "\u00c0\u00c8G"}
a6366cbd6750dc25ceba65dce8fe01f283b52ad189f2b54ba1bfb39c7a0b96d3

我需要在 ruby​​ 代码中进行哪些更改以使其输出与 python 输出相同(至少是最终哈希)?

注意事项:

  • 我尝试了this SO question(和其他人)的方法,但没有成功。
  • 上面的代码在只使用英文字符时产生相同的结果,所以我知道散列是相同的。

【问题讨论】:

  • 出于好奇,为什么? JSON 通常使用内容类型application/json; charset=utf-8 传输,因此只需在 JSON 中包含这些字符就可以了。
  • 好问题。我正在尝试将更长的 python 代码移植到 ruby​​。它涉及一些 AWS4 签名(不好玩......)。我的端口在使用英文字符作为输入时工作,而在使用非英文字符时我从 AWS4 收到错误。上面的问题是我指出的两个实现之间的第一个区别。
  • 好的。过去我不得不为 Facebook Graph API 做类似的事情,所以我理解。 Ruby 和 Python 只是以不同的方式处理这些事情。比如,为什么 Python 示例中\u00c8G 中的“c”是小写的,而“G”是大写的?我可以向您展示如何在 Ruby 中将其转换为这些转义序列,但是 Ruby 将所有字母字符大写,这使得正确处理非常棘手。
  • 哦,herp,这是输入数据中的 G。正确的。为您制定解决方案。

标签: ruby utf-8


【解决方案1】:

肯定有人会提出一个更优雅(或至少更高效、更健壮)的解决方案,但暂时是这样的:

#!/usr/bin/env ruby

require 'json'
require 'digest'

text = 'ÀÈG'
  .encode('UTF-16')                          # convert UTF-8 characters to UTF-16
  .inspect                                   # escape UTF-16 characters and convert back to UTF-8
  .sub(/^"\\u[Ff][Ee][Ff][Ff](.*?)"$/, '\1') # remove outer quotes and BOM
  .gsub(/\\u\w{4}/, &:downcase!)             # downcase alphas in escape sequences

js = { data: text }                          # wrap in containing data structure
  .to_json(:space=>' ')                      # convert to JSON with spaces after colons
  .gsub(/\\\\u(?=\w{4})/, '\\u')             # remove extra backslashes

puts 'Ruby:', js, Digest::SHA256.hexdigest(js)

输出:

$ ./test.rb 
Ruby:
{"data": "\u00c0\u00c8G"}
a6366cbd6750dc25ceba65dce8fe01f283b52ad189f2b54ba1bfb39c7a0b96d3

【讨论】:

  • 哇,真是一口…… :) - 感谢您的努力和有据可查的答案。
  • 不客气!正如我上面提到的,我以前曾为此苦苦挣扎过,所以我很清楚从哪里开始。祝你好运!
  • 如果不出意外,这个答案让我认为问题出在其他地方。一旦我进行了更多测试,并且一旦其他有启发性的答案的机会消失,我当然会接受答案。
  • @DannyB 问题在于,您尝试移植的现有代码依赖于 Python 1. 将数据编码为 UTF-16、2. 表示 UTF 转义序列和 3. 的非常具体的方式。格式编码的 JSON。 Ruby 的做法不同——没有错,只是不同——而且校验和不匹配。仅使用 UTF-8 数据(这是完全有效的 JSON)就可以避免所有或大部分情况,但不幸的是,您正在处理具有一些必须模仿的“怪癖”的外部系统。
猜你喜欢
  • 2023-03-29
  • 2013-03-13
  • 1970-01-01
  • 2016-04-08
  • 2020-05-22
  • 2012-07-15
  • 2017-05-28
  • 1970-01-01
相关资源
最近更新 更多