为了账号安全,请及时绑定邮箱和手机立即绑定

哪个是处理大 json 和替换特定值的最佳方法?

哪个是处理大 json 和替换特定值的最佳方法?

Go
SMILET 2021-11-01 17:17:37
我有一个很大的 json (30mb),其中包含不同对象中的“标题”字段,json 的结构未知。只知道 json 包含键“title”,这个键的字符串值必须转换成另一个。{    "data1" : {        "title" : "alpha",        "color" : "green"    },    "data2" : {        "someInnerData1" : {            "title" : "beta"            "color" : "red"        },        "someInnerData2" : {            "someArray" : [            {                "title" : "gamme",                "color" : "orange"            },            {                "title" : "delta",                "color" : "purple"            }            ],            "title" : "epsilon"        }    }}替换示例“alpha”->“Α”“beta”->“B”等。在 Golang 中实现这一目标的最佳方法是什么,而无需解码为 struct ?PS Json 从网络接收。
查看完整描述

2 回答

?
人到中年有点甜

TA贡献1895条经验 获得超7个赞

我会创建一个实现io.Reader接口的结构,并使用该读取器作为翻译基础:您可以使用它来逐块获取 JSON 输入,并检测您何时使用需要更改的键,因此将其翻译苍蝇。

然后,您只需使用 aio.Copy将整个文件读入另一个文件。

有关示例,请参阅text.transform包依赖关系图...


查看完整回答
反对 回复 2021-11-01
?
POPMUISE

TA贡献1765条经验 获得超5个赞

您可以使用像megajson这样的流式 JSON 解码器:


// Transform 'title' strings into Title case

func TitleizeJSON(r io.Reader, w io.Writer) error {

    buf := new(bytes.Buffer)

    r = io.TeeReader(r, buf)


    s := scanner.NewScanner(r)

    var prevTok int

    var prevPos int

    wasTitle := false

    titleField := []byte("title")

    for {

        // read the next json token

        tok, data, err := s.Scan()

        if err == io.EOF {

            return nil

        } else if err != nil {

            return err

        }

        // calculate the position in the buffer

        pos := s.Pos()

        off := pos - prevPos


        switch tok {

        // if this is a string

        case scanner.TSTRING:

            // if the previous string before a : was 'title', then

            // titlelize it

            if prevTok == scanner.TCOLON && wasTitle {

                // grab the first part of the buffer and skip

                // the first ", the titleize the rest

                data = buf.Bytes()[:off][1:]

                copy(data, bytes.Title(data))

                wasTitle = false

            } else {

                wasTitle = bytes.Equal(data, titleField)

            }

        }


        // now send the data to the writer

        data = buf.Bytes()

        _, err = w.Write(data[:off])

        if err != nil {

            return err

        }


        // reset the buffer (so it doesn't grow forever)

        nbuf := make([]byte, len(data)-off)

        copy(nbuf, data[off:])

        buf.Reset()

        buf.Write(nbuf)


        // for the next go-around

        prevTok = tok

        prevPos = pos

    }

}

这应该可以即时进行标题化。我能想到的一个问题是,如果你有一个非常大的字符串。


查看完整回答
反对 回复 2021-11-01
  • 2 回答
  • 0 关注
  • 179 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信