使用 \u0000 \x00 去 json.Unmarshal 键

这是 Go游乐场链接。


基本上'\u0000',我的 JSON 字符串键中有一些特殊字符 ( ):


var j = []byte(`{"Page":1,"Fruits":["5","6"],"\u0000*\u0000_errorMessages":{"x":"123"},"*_successMessages":{"ok":"hi"}}`)

我想将它解组为一个结构:


type Response1 struct {

    Page   int

    Fruits []string

    Msg    interface{} `json:"*_errorMessages"`

    Msg1   interface{} `json:"\\u0000*\\u0000_errorMessages"`

    Msg2   interface{} `json:"\u0000*\u0000_errorMessages"`

    Msg3   interface{} `json:"\0*\0_errorMessages"`

    Msg4   interface{} `json:"\\0*\\0_errorMessages"`

    Msg5   interface{} `json:"\x00*\x00_errorMessages"`

    Msg6   interface{} `json:"\\x00*\\x00_errorMessages"`

    SMsg   interface{} `json:"*_successMessages"`

}

我尝试了很多,但它不起作用。此链接可能对golang.org/src/encoding/json/encode_test.go有所帮助。


收到一只叮咚
浏览 367回答 3
3回答

哈士奇WWW

简短回答:在当前的json实现中,不可能只使用struct tags。注意:这是一个实现限制,而不是规范限制。(这是json包实现的限制,而不是结构标签规范的限制。)一些背景:您使用原始字符串文字指定了标签:原始字符串文字的值是由引号之间的未解释(隐式 UTF-8 编码)字符组成的字符串...因此,编译器不会在原始字符串文字的内容中进行转义或取消引用。引用自 struct 标记值的约定reflect.StructTag:按照惯例,标签字符串是可选的空格分隔键:“值”对的串联。每个键都是一个非空字符串,由除空格 (U+0020 ' ')、引号 (U+0022 '"') 和冒号 (U+003A ':') 以外的非控制字符组成。每个值都用引号引起来使用 U+0022 '"' 字符和 Go 字符串文字语法。这意味着按照惯例标签值是由空格分隔的 (key:"value") 对列表。有钥匙不少限制,但值可以是任何东西,和值(应该)使用“去串文字语法”,这意味着这些值将在运行时从代码中加引号(通过一个电话strconv.Unquote(),叫from StructTag.Get(),在源文件reflect/type.go,当前行 #809)。所以不需要双引号。请参阅您的简化示例:type Response1 struct {&nbsp; &nbsp; Page&nbsp; &nbsp;int&nbsp; &nbsp; Fruits []string&nbsp; &nbsp; Msg&nbsp; &nbsp; interface{} `json:"\u0000_abc"`}现在下面的代码:t := reflect.TypeOf(Response1{})fmt.Printf("%#v\n", t.Field(2).Tag)fmt.Printf("%#v\n", t.Field(2).Tag.Get("json"))印刷:"json:\"\\u0000_abc\"""\x00_abc"如您所见,json键的值部分是"\x00_abc"正确包含零字符的。但是json包将如何使用它?该json包使用返回的值StructTag.Get()(从reflect包装),正是我们所做的。您可以在json/encode.go源文件typeFields()函数中看到它,当前行 #1032。到现在为止还挺好。然后它调用源文件中未导出的json.parseTag()函数json/tags.go,当前行#17。这会剪切逗号后面的部分(成为“标签选项”)。最后json.isValidTag()使用源文件中的前一个值调用函数json/encode.go,当前行#731。此函数检查传递的符文string,并且(除了一组预定义的允许字符"!#$%&()*+-./:<=>?@[]^_{|}~ ")拒绝不是 Unicode 字母或数字(由unicode.IsLetter()和定义unicode.IsDigit())的所有内容:if !unicode.IsLetter(c) && !unicode.IsDigit(c) {&nbsp; &nbsp; return false}&nbsp;'\u0000' 不是预定义的允许字符的一部分,您现在可以猜到,它既不是字母也不是数字:// Following code prints "INVALID":c := '\u0000'if !unicode.IsLetter(c) && !unicode.IsDigit(c) {&nbsp; &nbsp; fmt.Println("INVALID")}并且由于isValidTag()返回false,name(这是json键的值,没有“标签选项”部分)将被丢弃(name = "")并且不被使用。因此,将找不到包含 unicode 零的 struct 字段的匹配项。对于替代解决方案,请使用map、自定义json.Unmarshaler或使用json.RawMessage。但我非常不鼓励使用这种丑陋的 json 键。我知道您可能只是想解析这样的 json 响应,它可能超出您的范围,但是您应该反对使用这些键,因为它们只会在以后引起更多问题(例如,如果存储在 db 中,通过检查记录它会很难发现其中有'\u0000'字符,因为它们可能会显示为空)。

largeQ

我认为 struct 标签不可能做到这一点。您可以做的最好的事情是将其解组map[string]interface{},然后手动获取值:var b = []byte(`{"\u0000abc":42}`)var m map[string]interface{}err := json.Unmarshal(b, &m)if err != nil {&nbsp; &nbsp; panic(err)}fmt.Println(m, m["\x00abc"])游乐场:http : //play.golang.org/p/RtS7Nst0d7。

青春有我

由于以下原因,您不能这样做:http&nbsp;:&nbsp;//golang.org/ref/spec#Struct_types但是您可以解组,map[string]interface{}然后通过regexp检查该对象的字段名称。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go