如何解析ovs-vsctl获取接口<interface>统计信息的结果

时间:2015-10-13 09:36:31

标签: parsing go

结果示例:

{collisions=0, rx_bytes=258, rx_crc_err=0, rx_dropped=0, rx_errors=0, rx_frame_err=0, rx_over_err=0, rx_packets=3, tx_bytes=648, tx_dropped=0, tx_errors=0, tx_packets=8}

此格式类似于JSON,但不是JSON。

有没有一种简单的方法可以将其解析为map[string]int?与json.Unmarshal(data, &value)一样。

2 个答案:

答案 0 :(得分:1)

如果不以递归方式定义该传输格式,即密钥无法启动子结构,则其语言为regular。因此,您可以使用Go的标准regexp包正确解析它:

Playground link

package main

import (
    "fmt"
    "regexp"
    "strconv"
)

const data = `{collisions=0, rx_bytes=258, rx_crc_err=0, rx_dropped=0, rx_errors=0, rx_frame_err=0, rx_over_err=0, rx_packets=3, tx_bytes=648, tx_dropped=0, tx_errors=0, tx_packets=8}`

const regex = `([a-z_]+)=([0-9]+)`

func main() {
    ms := regexp.MustCompile(regex).FindAllStringSubmatch(data, -1)

    vs := make(map[string]int)

    for _, m := range ms {
        v, _ := strconv.Atoi(m[2])
        vs[m[1]] = v
    }

    fmt.Printf("%#v\n", vs)
}

答案 1 :(得分:0)

@thwd的Regexp是一个优雅的解决方案。

您可以使用strings.Split()分隔逗号空格(", ")来获取对,然后再用等号("=")拆分,从而获得更有效的解决方案获得键值对。之后,您只需将这些放入地图中:

func Parse(s string) (m map[string]int, err error) {
    if len(s) < 2 || s[0] != '{' || s[len(s)-1] != '}' {
        return nil, fmt.Errorf("Invalid input, no wrapping brackets!")
    }

    m = make(map[string]int)
    for _, v := range strings.Split(s[1:len(s)-1], ", ") {
        parts := strings.Split(v, "=")
        if len(parts) != 2 {
            return nil, fmt.Errorf("Equal sign not found in: %s", v)
        }
        if m[parts[0]], err = strconv.Atoi(parts[1]); err != nil {
            return nil, err
        }
    }
    return
}

使用它:

s := "{collisions=0, rx_bytes=258, ...}"

fmt.Println(Parse(s))

Go Playground 上试试。

注意:如果性能很重要,可以通过在外部循环中不使用strings.Split()来改进,而是手动搜索逗号&#34;并保持指数,只有&#34;取出&#34;表示实际键和值的子串(但这种解决方案会更复杂)。

另一种解决方案......

...但是此选项要慢得多,因此只有在性能不是关键要求时才可行:您可以将输入字符串转换为有效的JSON格式,之后可以使用json.Unmarshal()。错误检查省略:

s := "{collisions=0, rx_bytes=258, ...}"

// Turn into valid JSON:
s = strings.Replace(s, `=`, `":`, -1)
s = strings.Replace(s, `, `, `, "`, -1)
s = strings.Replace(s, `{`, `{"`, -1)

// And now simply unmarshal:
m := make(map[string]int)
json.Unmarshal([]byte(s), &m)
fmt.Println(m)

此解决方案的优点在于,如果您隐藏的目标值为struct,这也有效:

// Unmarshal into a struct (you don't have to care about all fields)
st := struct {
    Collisions int `json:"collisions"`
    Rx_bytes   int `json:"rx_bytes"`
}{}
json.Unmarshal([]byte(s), &st)
fmt.Printf("%+v\n", st)

Go Playground 上试试这些。