给出以下示例:
func main() {
buf := new(bytes.Buffer)
enc := json.NewEncoder(buf)
toEncode := []string{"hello", "wörld"}
enc.Encode(toEncode)
fmt.Println(buf.String())
}
我希望输出带有转义的 Unicode 字符:
[“你好”,“w\u00f6rld”]
而不是:
[“你好”,“世界”]
我尝试编写一个函数来使用
strconv.QuoteToASCII
引用 Unicode 字符并将结果提供给 Encode()
,但这会导致双重转义:
func quotedUnicode(data []string) []string {
for index, element := range data {
quotedUnicode := strconv.QuoteToASCII(element)
// get rid of additional quotes
quotedUnicode = strings.TrimSuffix(quotedUnicode, "\"")
quotedUnicode = strings.TrimPrefix(quotedUnicode, "\"")
data[index] = quotedUnicode
}
return data
}
[“你好”,“w\u00f6rld”]
如何确保 json.Encode 的输出包含正确转义的 Unicode 字符?
encoding/json
软件包不支持此功能,但您可以自己实现。
对于结构体的每个字符串字段,将其类型从
string
更改为 json.RawMessage
并使用以下函数引用它:
func QuoteToJSON(s string) json.RawMessage {
var sb strings.Builder
for _, r := range s {
if r > 0xFFFF {
r1, r2 := utf16.EncodeRune(r)
sb.WriteString(fmt.Sprintf("\\u%04X", r1))
sb.WriteString(fmt.Sprintf("\\u%04X", r2))
} else if r > 0x7F {
sb.WriteString(fmt.Sprintf("\\u%04X", r))
} else {
sb.WriteRune(r)
}
}
return json.RawMessage(`"` + sb.String() + `"`)
}
完整示例:
type Greeting struct {
Text string
}
func (g *Greeting) MarshalJSON() ([]byte, error) {
return json.Marshal(&struct {
Text json.RawMessage `json:"text"`
}{
Text: QuoteToJSON(g.Text),
})
}
func main() {
out := Greeting{"Hí, 😊!"}
dat, _ := json.Marshal(&out)
fmt.Println(string(dat)) // {"text":"H\u00ED, \uD83D\uDE0A!"}
var in Greeting
json.Unmarshal(dat, &in)
fmt.Println(in.Text) // "Hí, 😊!"
}
去游乐场:https://go.dev/play/p/Jk6GZwdvyvm
有些人建议使用
strconv.QuoteToASCII
但这有两个问题:
"\\u4e09"
而不是 "\u4e09"
。"😊"
应编码为 \ud83d\ude0a
而不是 \U0001f60a
。