Go语言JSON编码:如何用转义替代Unicode替换避免数据丢失?
Go语言实现JSON字符串转义而非替换的方法
当运行以下Go代码时:
package main import ( "encoding/json" "os" ) func main() { json.NewEncoder(os.Stdout).Encode("\xa1") // 输出 "\ufffd" }
会出现数据丢失问题——Go标准库的encoding/json编码器遇到无效UTF-8字节时,会自动替换成Unicode替换字符\ufffd,导致原始值无法恢复。而Python的json.dumps会将这类字节转义为\u00a1,解码后能完全还原原始内容:
import json a = '\xa1' b = json.dumps(a) # 输出 "\u00a1" print(json.loads(b) == a) # 输出 True
Go标准库默认不支持这种转义行为,但可以通过自定义JSON序列化类型实现,核心是手动处理每个字节,将非ASCII或控制字符转义为\uXXXX格式而非替换。示例代码如下:
package main import ( "bytes" "encoding/json" "fmt" "os" ) // 自定义字符串类型,实现json.Marshaler接口 type RawString string func (s RawString) MarshalJSON() ([]byte, error) { var buf bytes.Buffer buf.WriteByte('"') for _, b := range []byte(s) { switch { case b == '"' || b == '\\': // 转义引号和反斜杠 buf.WriteByte('\\') buf.WriteByte(b) case b < 0x20: // 转义控制字符 buf.WriteString(fmt.Sprintf("\\u%04x", b)) case b >= 0x80: // 转义非ASCII字节为\u00XX格式 buf.WriteString(fmt.Sprintf("\\u%04x", b)) default: // 普通ASCII字符直接写入 buf.WriteByte(b) } } buf.WriteByte('"') return buf.Bytes(), nil } func main() { // 使用自定义类型编码,输出 "\u00a1" json.NewEncoder(os.Stdout).Encode(RawString("\xa1")) // 验证解码后是否与原始值一致 var decoded string encoded, _ := json.Marshal(RawString("\xa1")) json.Unmarshal(encoded, &decoded) fmt.Println(decoded == "\xa1") // 输出 true }
说明:
- 自定义
RawString类型实现了json.Marshaler接口,手动控制JSON序列化流程; - 遍历字符串的每个字节,对需要转义的字符(引号、反斜杠、控制字符、非ASCII字节)统一处理为
\uXXXX格式; - 生成的JSON字符串行为与Python的
json.dumps一致,解码后可完全恢复原始数据。
内容的提问来源于stack exchange,提问作者user20619147
相关产品推荐
相关产品推荐

