在json编码golang中转义unicode字符

问题描述 投票:0回答:1

给出以下示例:

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 字符?

go unicode encoding character-encoding
1个回答
0
投票

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
但这有两个问题:

  1. 字符串在编组时将进行双重转义,例如它们看起来像
    "\\u4e09"
    而不是
    "\u4e09"
  2. JSON 要求基本多语言平面之外的字符使用 UTF-16 代理项进行编码,例如字符串
    "😊"
    应编码为
    \ud83d\ude0a
    而不是
    \U0001f60a
© www.soinside.com 2019 - 2024. All rights reserved.