繁体   English   中英

使用 json.loads() 保留 unicode 字符或在执行 json.dumps() 时将它们转换回

[英]preserve unicode characters with json.loads() or convert them back to when doing a json.dumps()

我有一个 json 文件,其中包含 unicode 字符\<\> \< 使用 json.load() 加载文件时,这些字符会转换为<> 考虑以下实验:

d = json.loads('"Foo \u003cfoo@bar.net\u003e"')

然后打印如下:

'Foo <foo@bar.net>'

假设我需要将其转储回文件,并且需要将字符<>转换回\<\> \< 我目前正在使用f.write(json.dumps(d))但这似乎不起作用。

我已经搜索了几个小时,但无法弄清楚这一点。

好吧,在这里了解 Python 解释器在做什么会很有用。

当解释器找到字符串字面量的开头时

在你的源代码中,你有这样一段文字:

'"Foo \u003cfoo@bar.net\u003e"'

当解析器找到第一个字符' ,它得出结论:“这是一个字符串文字!在找到下一个' ,我应该获取所有字符并将其放入一个列表中,以用作字符串。” 因此,假设它在内存中创建了以下列表:

[]

然后它找到下一个字符" 。由于字符串文字没有关闭(因为没有找到' ),它将它添加到列表中。作为计算机中的一切,字符都表示为数字。数字是它的 Unicode 点,对于"代码点是 34:

[ 34 ]
#  "

它对下一个字符执行相同的操作,将它们的代码点放在列表中:

[ 34   70  111  111   32 ]
#  "    F    o    o       

源代码中的\\u字符

现在,解释器找到了字符\\ 但这根本不是一个常见的字符! 对于解释器来说,这意味着接下来的字符不代表他们自己,而是应该被解释。 所以解释器不会\\添加到列表中,并让下一个解释器了解应该做什么。 这就是结果中没有\\的原因。

下一个字符是u 由于它以\\为前缀,解释器不会将其插入到列表中。 相反, \\u\u003c/code>对被解释为获取接下来的四个字符的命令,并将它们转换为十六进制数。 这就是结果中没有\\u\u003c/code>的原因。

六个字符如何变成只有一个

接下来的四个字符是003c 它们形成 0x3C 十六进制数,即十进制形式的 60。 所以它被添加到列表中:

[ 34   70  111  111   32   60 ]
#  "    F    o    o         <

好吧,60 在 Unicode 中是< 这就是为什么你的结果中有一个< 这就是为什么六个字符( \\u003c )在程序运行时实际上只代表一个( > )的原因。

如何得到你想要的

当然,您可能希望在结果字符串中包含字符\\u等。 如果是这样,Python 会给你一些选择,最简单的一个是原始字符串文字 为此,您只需要在字符串文字前加上r前缀,如下所示:

r'"Foo \u003cfoo@bar.net\u003e"'

当解释器解析源代码中的r ,然后是引号(例如' )时,它知道它是一个字符串文字,但该字符串文字根本没有解释\\ 它里面的所有东西都将按照在源代码中输入的方式使用。 这带来了类似于您似乎想要的结果:

>>> print('"Foo \u003cfoo@bar.net\u003e"')
"Foo <foo@bar.net>"
>>> print(r'"Foo \u003cfoo@bar.net\u003e"')
"Foo \u003cfoo@bar.net\u003e"

小心你的愿望

但是请注意,这些字符串完全不同! 甚至它们的大小也大不相同,因为第二个字符更多:

>>> len('"Foo \u003cfoo@bar.net\u003e"')
19
>>> len(r'"Foo \u003cfoo@bar.net\u003e"')
29

现在,我不得不说,您可能不想在这里使用原始字符串 您可能只想用 Unicode 点表示字符串,但这也引出了为什么. 无论如何,现在由你决定你想要什么:)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM