JSON encode golang中的转义Unicode字符

wrrgggsh  于 2023-11-14  发布在  Go
关注(0)|答案(1)|浏览(139)

举个例子:

func main() {
    buf := new(bytes.Buffer)
    enc := json.NewEncoder(buf)
    toEncode := []string{"hello", "wörld"}
    enc.Encode(toEncode)
    fmt.Println(buf.String())
}

字符串
我想让输出显示转义的Unicode字符:
[“hello”,“w\u00f6rld”]
而不是:
[“hello”,“wörld”]
我尝试编写一个函数,使用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                                                             
}


[“hello”,“w\u00f6rld”]
如何确保json.Encode的输出包含正确转义的Unicode字符?

xj3cbfub

xj3cbfub1#

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í, 😊!"
}


Go playground:https://go.dev/play/p/Jk6GZwdvyvm
有些人建议使用strconv.QuoteToASCII,但这有两个问题:
1.字符串在被封送时将被双转义,例如,它们看起来像"\\u4e09"而不是"\u4e09"

  1. JSON要求基本多语言平面之外的字符使用UTF-16代理编码,例如字符串"😊"应编码为"\ud83d\ude0a"而不是"\U0001f60a"

相关问题