如果我运行这个Go代码:
package main
import (
"encoding/json"
"os"
)
func main() {
json.NewEncoder(os.Stdout).Encode("xa1") // "ufffd"
}
我丢失了数据,因为一旦Unicode替换完成,我就不能再得到返回原始值。与以下Python代码比较:
import json
a = 'xa1'
b = json.dumps(a) # "u00a1"
print(json.loads(b) == a) # True
没有替换,所以没有数据丢失。另外,生成的JSON是仍然有效。Go有一些方法来编码JSON字符串与转义而不是替换?
这个例子是一个假等价。'xa1'
在Python中是一个有效的Unicode字符串,它只是一种可能的表示形式,如'u00a1'
或'U000000a1'
或chr(0xa1)
或'N{INVERTED EXCLAMATION MARK}'
或'¡'
或…
在Python代码中等效为:
>>> print(json.dumps(b'xa1'.decode(errors='replace')))
"ufffd"
在标准输出时也打印强制替换字符的ascii表示形式,与Go中相同。
这是因为"xa1"
不是一个有效的Unicode字符串。它包含字节0xa1
,这是无效的(本身无效)。无效字节将被U+FFFD替换,这是"替换字符"-在输入无效时使用。
如果要编码Unicode字符U+00A1,则将其写成"u00a1"
。如果您想让任意数据通过JSON来回传输,则必须以不同的方式表示它(例如,像base64编码它)。
Python的工作方式不同——在Python中,xa1
转义序列是U+00A1。同样,在Go中,xa1
是字节0xa1
,它本身不是一个有效的Unicode字符串,并且不能被编码为JSON字符串。