3

我想将 dict 转储为包含一些中文字符的 json 字符串,并用它格式化一个 url 请求参数。

这是我的python代码:

import httplib
import simplejson as json
import urllib

d={
  "key":"上海",
  "num":1
}

jsonStr = json.dumps(d,encoding='gbk')
url_encode=urllib.quote_plus(jsonStr)

conn = httplib.HTTPConnection("localhost",port=8885)
conn.request("GET","/?json="+url_encode)
res = conn.getresponse()

我对请求字符串的期望是这样的:

GET /?json=%7B%22num%22%3A+1%2C+%22key%22%3A+%22%C9%CF%BA%A3%22%7D
                                                ------------
                                                     |
                                                     V
                       "%C9%CF%BA%A3" represent "上海" in format of 'gbk' in url.

但我得到的是:

GET /?json=%7B%22num%22%3A+1%2C+%22key%22%3A+%22%5Cu6d93%5Cu5a43%5Cu6363%22%7D
                                                ------------------------
                                                         |
                                                         v
           %5Cu6d93%5Cu5a43%5Cu6363  is 'some' format of chinese characters "上海"  

我还尝试使用ensure_ascii=False以下选项转储 json:

jsonStr = json.dumps(d,ensure_ascii=False,encoding='gbk')

但没有运气。

那么,我怎样才能使这项工作?谢谢。

4

2 回答 2

2

你几乎得到了它ensure_ascii=False。这有效:

jsonStr = json.dumps(d, encoding='gbk', ensure_ascii=False).encode('gbk')

您需要告知json.dumps()它将读取的字符串是 GBK,并且不应尝试对它们进行 ASCII 化处理。然后您必须重新指定输出编码,因为json.dumps()没有单独的选项。

此解决方案类似于此处的另一个答案:https ://stackoverflow.com/a/18337754/4323

所以这就是你想要的,尽管我应该注意 URI 的标准似乎说它们应该尽可能使用 UTF-8。有关更多信息,请参见此处:https ://stackoverflow.com/a/14001296/4323

于 2014-10-09T05:09:56.283 回答
1
"key":"上海",

您将源代码保存为 UTF-8,所以这是 byte string '\xe4\xb8\x8a\xe6\xb5\xb7'

jsonStr = json.dumps(d,encoding='gbk')

JSON 格式仅支持 Unicode 字符串。该encoding参数可用于强制json.dumps允许字节字符串,使用给定的编码自动将它们解码为 Unicode。

但是,字节字符串的编码实际上不是 UTF-8 'gbk',所以json.dumps解码不正确,给出u'涓婃捣'. 然后它会生成不正确的 JSON 输出"\u6d93\u5a43\u6363",并将其 URL 编码为%22%5Cu6d93%5Cu5a43%5Cu6363%22.

要解决此问题,您应该输入json.dumps正确的 Unicode ( u'') 字符串:

# coding: utf-8

d = {
    "key": u"上海",  # or u'\u4e0a\u6d77' if you don't want to rely on the coding decl
    "num":1
}
jsonStr = json.dumps(d)
...

这将为您提供 JSON "\u4e0a\u6d77",编码为 URL %22%5Cu4e0a%5Cu6d77%22

如果你真的不想\u在你的 JSON 中转义,你确实可以在 URL 编码之前输出ensure_ascii=False.encode()但我不会推荐它,因为这样您就不得不担心目标应用程序在其 URL 参数中需要什么编码,这是一些痛苦的根源。该\u版本被所有 JSON 解析器接受,并且通常在 URL 编码后不会更长。

于 2014-10-09T08:04:31.980 回答