Golang中如何避免JSON解码器移除字符串中的反斜杠字符

Golang中如何避免JSON解码器移除字符串中的反斜杠字符 我有一个如下所示的JSON字符串:

{“toDb”:“BEGIN let rs1 resultset := (\u0002); let rs2 resultset := select c2 from t1 where RLIKE(c1,‘\d+’); END;“}

当我将这个JSON字符串解码到一个结构体中时,它会移除转义字符。这不是我期望的结果。那么,我该如何避免这种行为呢?以下是示例代码链接:Go Playground - The Go Programming Language


更多关于Golang中如何避免JSON解码器移除字符串中的反斜杠字符的实战教程也可以访问 https://www.itying.com/category-94-b0.html

4 回复

听起来真正的修复必须应用于JSON的源头……

使用 RawMessage 感觉像是针对错误输入的一种变通方法,而非真正的修复……

更多关于Golang中如何避免JSON解码器移除字符串中的反斜杠字符的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


我通过使用 map[string]json.RawMessage 作为解码的结构体找到了解决方案。感谢您的回复。

我没有看到任何内容被移除。

反序列化后的数据中,转义字符得到了正确的表示。

如果你想表示字符串 \u0002\\d,而不是字节 0x02 或字符串 \d,你需要在 JSON 中添加额外的转义。即 \\u0002\\\\d

在Go中,JSON解码器会自动处理转义字符,这是符合JSON规范的行为。要保留原始字符串中的反斜杠,你需要使用json.RawMessage或自定义解码逻辑。以下是解决方案:

方案1:使用json.RawMessage保留原始JSON

package main

import (
    "encoding/json"
    "fmt"
)

type MyStruct struct {
    ToDb json.RawMessage `json:"toDb"`
}

func main() {
    jsonStr := `{"toDb":"BEGIN let rs1 resultset := (\\u0002); let rs2 resultset := select c2 from t1 where RLIKE(c1,'\\d+'); END;"}`
    
    var data MyStruct
    if err := json.Unmarshal([]byte(jsonStr), &data); err != nil {
        panic(err)
    }
    
    // 直接使用原始JSON数据
    fmt.Printf("原始JSON字段: %s\n", string(data.ToDb))
    
    // 如果需要获取字符串值(仍会处理转义)
    var toDbStr string
    if err := json.Unmarshal(data.ToDb, &toDbStr); err != nil {
        panic(err)
    }
    fmt.Printf("解码后的字符串: %s\n", toDbStr)
}

方案2:自定义JSON解码

package main

import (
    "encoding/json"
    "fmt"
    "strings"
)

type CustomString string

func (cs *CustomString) UnmarshalJSON(data []byte) error {
    // 去除JSON字符串两端的引号
    if len(data) >= 2 && data[0] == '"' && data[len(data)-1] == '"' {
        // 保留原始内容,不进行转义处理
        *cs = CustomString(data[1 : len(data)-1])
        return nil
    }
    // 如果不是字符串类型,按默认方式处理
    var s string
    if err := json.Unmarshal(data, &s); err != nil {
        return err
    }
    *cs = CustomString(s)
    return nil
}

type MyStruct struct {
    ToDb CustomString `json:"toDb"`
}

func main() {
    jsonStr := `{"toDb":"BEGIN let rs1 resultset := (\\u0002); let rs2 resultset := select c2 from t1 where RLIKE(c1,'\\d+'); END;"}`
    
    var data MyStruct
    if err := json.Unmarshal([]byte(jsonStr), &data); err != nil {
        panic(err)
    }
    
    fmt.Printf("保留反斜杠的字符串: %s\n", data.ToDb)
    fmt.Printf("包含原始转义字符: %q\n", string(data.ToDb))
}

方案3:使用原始字符串处理

package main

import (
    "encoding/json"
    "fmt"
)

type MyStruct struct {
    ToDb string `json:"toDb"`
}

func main() {
    // 注意:在Go字符串字面量中,反斜杠需要转义
    jsonStr := `{"toDb":"BEGIN let rs1 resultset := (\\u0002); let rs2 resultset := select c2 from t1 where RLIKE(c1,'\\d+'); END;"}`
    
    var data MyStruct
    if err := json.Unmarshal([]byte(jsonStr), &data); err != nil {
        panic(err)
    }
    
    // 重新编码以查看实际存储的内容
    output, _ := json.Marshal(data)
    fmt.Printf("重新编码的JSON: %s\n", output)
    fmt.Printf("存储的字符串值: %s\n", data.ToDb)
}

关键点说明:

  1. JSON规范要求:JSON解码器必须处理转义序列,\u0002会被解码为Unicode字符,\d中的反斜杠会被移除。

  2. 字符串字面量转义:在Go代码中定义JSON字符串时,反斜杠需要双重转义:

    • \\u0002 → JSON中的\u0002
    • \\d+ → JSON中的\d+
  3. 验证JSON有效性

func validateJSON(jsonStr string) {
    var raw map[string]interface{}
    if err := json.Unmarshal([]byte(jsonStr), &raw); err != nil {
        fmt.Printf("JSON无效: %v\n", err)
    } else {
        fmt.Println("JSON有效")
    }
}

选择哪种方案取决于你的具体需求:如果需要完全保留原始JSON格式,使用json.RawMessage;如果需要自定义处理逻辑,实现自定义的UnmarshalJSON方法。

回到顶部