簡體   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