这是处理大型json& amp;的最佳方式。替换特定值?

时间:2015-09-01 09:28:38

标签: json go

我有一个大json(30mb),其中包含不同对象中的“title”字段,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?

P.S。 Json是从网络收到的。

2 个答案:

答案 0 :(得分:0)

我会创建一个实现io.Reader接口的结构,并使用该读取器作为转换基础:您可以使用它来获取块的JSON输入块,并检测何时使用需要的键要改变,所以即时翻译。

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

请参阅text.transform包依赖关系图以获取示例...

答案 1 :(得分:0)

您可以使用像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
    }
}

这应该在飞行中进行标题化。我能想到的一个问题就是如果你有一个非常大的字符串。