使用json.loads()保留Unicode字符,或在执行json.dumps()时将其转换回

时间:2018-08-21 16:30:33

标签: python json

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

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

然后打印如下:

'Foo <foo@bar.net>'

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

我已经搜索了几个小时,但只是无法弄清楚。

1 个答案:

答案 0 :(得分:0)

好吧,在这里了解Python解释器的工作将很有用。

解释器找到字符串文字的开头

在源代码中,您有以下一段文字:

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

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

[]

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

[ 34 ]
#  "

它与下一个字符相同,将其代码点放在列表中:

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

源代码中的\u字符

现在,解释器找到字符\。但这根本不是普通字符!对解释者而言,这意味着下一个字符不代表自身,而应被解释。因此,解释器不会\添加到列表中,并让下一个解释器了解应执行的操作。 这就是为什么您的结果中没有\的原因。

下一个字符是u。由于其前缀为\,因此解释程序不会将其插入列表。相反,the \u pair is interpreted as a command可以获取接下来的四个字符,并将它们转换为十六进制数字。 这就是为什么您的结果中没有\u的原因。

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

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

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

好吧,Unicode中的60是<这就是为什么您的结果中有<的原因。这就是为什么六个字符(\u0,{{1} },03)实际上在程序运行时仅代表一个(c)。

如何获得想要的东西

当然,您可能希望结果字符串中包含字符>\等。如果是这样,Python提供了一些选项,最简单的选择是raw string literal。为此,只需在字符串文字前加上u即可,如下所示:

r

当解释器在源代码中查找r'"Foo \u003cfoo@bar.net\u003e"' 后再加上引号(例如r)时,它知道它是一个字符串文字,但是此字符串文字没有'完全被解释。它内部的所有内容都将按照在源代码中键入的内容使用。这样会带来类似于您想要的结果:

\

Be Careful What You Wish For

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

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

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