>我有一个 json 文件,其中包含 unicode 字符u003c
和u003e
。当使用 json.load(( 加载文件时,这些字符将转换为<
并>
。请考虑以下实验:
d = json.loads('"Foo u003cfoo@bar.netu003e"')
然后打印如下:
'Foo <foo@bar.net>'
假设我需要将其转储回文件,并且需要将字符<
和>
转换回u003c
和u003e
。我目前正在使用f.write(json.dumps(d))
但这似乎不起作用。
我已经搜索了几个小时,但就是无法弄清楚。
好吧,在这里了解Python解释器正在做什么会很有用。
当解释器找到字符串文本的开头时
在您的源代码中,您有以下一段文本:
'"Foo u003cfoo@bar.netu003e"'
当解析器找到第一个字符'
时,它得出结论:"这是一个字符串文字!在我找到下一个'
之前,我应该获取所有字符并将其放在列表中,以用作字符串。因此,假设它在内存中创建以下列表:
[]
然后它找到下一个字符,"
.由于字符串文本不是关闭的(因为没有找到'
(,它会将其添加到列表中。与计算机中的所有内容一样,字符表示为数字。该数字是其 Unicode 点,对于"
,代码点为 34:
[ 34 ]
# "
它对下一个字符执行相同的操作,将它们的代码点放在列表中:
[ 34 70 111 111 32 ]
# " F o o
源代码中的
和u
字符
现在,解释器找到字符。但这根本不是常见的字符!对于解释者来说,这意味着接下来的字符不是指他们自己,而是应该被解释。因此,口译员不会将
添加到列表中,而是让下一位口译员了解应该做什么。这就是为什么您的结果没有
的原因。
下一个字符是u
。因为它是以为前缀的,解释器不会将其插入到列表中。相反,
u
对被解释为获取接下来的四个字符的命令,将它们转换为十六进制数。这就是为什么您的结果中没有u
的原因。
六个字符如何变成一个
接下来的四个字符是0
、0
、3
和c
。它们形成0x3C十六进制数,即十进制形式的 60。因此,它被添加到列表中:
[ 34 70 111 111 32 60 ]
# " F o o <
好吧,60 在 Unicode 中<
。这就是为什么你的结果有<
。这就是为什么当程序运行时,六个字符(、
u
、0
、0
、3
、c
(实际上只代表一个(>
(。
如何得到你想要的
当然,您可能希望在结果字符串中包含字符、
u
等。如果是这样,Python 会给你一些选项,最简单的一个是原始字符串文字。为此,您只需要在字符串文字前面加上r
前缀,如下所示:
r'"Foo u003cfoo@bar.netu003e"'
当解释器在源代码中对r
进行修正,然后加上引号(如'
(时,它知道它是一个字符串文字,但这个字符串文字根本没有解释。它里面的所有内容都将按照在源代码中键入的内容使用。这带来了类似于您似乎想要的结果:
>>> print('"Foo u003cfoo@bar.netu003e"')
"Foo <foo@bar.net>"
>>> print(r'"Foo u003cfoo@bar.netu003e"')
"Foo u003cfoo@bar.netu003e"
小心你的愿望
但请注意,这些字符串是完全不同的!甚至它们的大小也大不相同,因为第二个有更多的字符:
>>> len('"Foo u003cfoo@bar.netu003e"')
19
>>> len(r'"Foo u003cfoo@bar.netu003e"')
29
现在,我不得不说,你可能不想在这里有一个原始字符串。您可能只想用 Unicode 点表示字符串,但它也回避了为什么的问题。无论如何,现在由您决定您想要什么:)