【问题标题】:Golang regular expression for parsing key value pair into a string map用于将键值对解析为字符串映射的 Golang 正则表达式
【发布时间】:2017-10-31 19:30:40
【问题描述】:

我希望使用正则表达式将以下字符串解析为 map[string]string

time="2017-05-30T19:02:08-05:00" level=info msg="some log message" app=sample size=10

我正在尝试创建一个地图

m["time"] = "2017-05-30T19:02:08-05:00"
m["level"] = "info"

我尝试过使用regex.FindAllStringIndex,但无法找到合适的正则表达式?这是正确的方法吗?

【问题讨论】:

标签: regex dictionary go


【解决方案1】:

这不是使用正则表达式,而只是一个示例,说明如何使用strings.FieldsFunc 实现相同的目的。

https://play.golang.org/p/rr6U8xTJZT

package main

import (
    "fmt"
    "strings"
    "unicode"
)

const foo = `time="2017-05-30T19:02:08-05:00" level=info msg="some log message" app=sample size=10`

func main() {
    lastQuote := rune(0)
    f := func(c rune) bool {
        switch {
        case c == lastQuote:
            lastQuote = rune(0)
            return false
        case lastQuote != rune(0):
            return false
        case unicode.In(c, unicode.Quotation_Mark):
            lastQuote = c
            return false
        default:
            return unicode.IsSpace(c)

        }
    }

    // splitting string by space but considering quoted section
    items := strings.FieldsFunc(foo, f)

    // create and fill the map
    m := make(map[string]string)
    for _, item := range items {
        x := strings.Split(item, "=")
        m[x[0]] = x[1]
    }

    // print the map
    for k, v := range m {
        fmt.Printf("%s: %s\n", k, v)
    }
}

【讨论】:

  • 这是我最终使用的,但 @kennytm 的解决方案同样好,前提是您可以接受额外的依赖。
【解决方案2】:

您可以简单地使用github.com/kr/logfmt package,而不是编写自己的正则表达式。

Package 实现了 logfmt 键值对的解码。

logfmt 消息示例:

foo=bar a=14 baz="hello kitty" cool%story=bro f %^asdf

JSON 格式的示例结果:

{ 
    "foo": "bar", 
    "a": 14, 
    "baz": "hello kitty", 
    "cool%story": "bro", 
    "f": true, 
    "%^asdf": true 
}

【讨论】:

    【解决方案3】:

    在正则表达式以及 FindStringSubmatch 和 SubexpNames 函数中使用命名的捕获组。例如:

    s := `time="2017-05-30T19:02:08-05:00" level=info msg="some log message" app=sample size=10`
    re := regexp.MustCompile(`time="(?P<time>.*?)"\slevel=(?P<level>.*?)\s`)
    values := re.FindStringSubmatch(s)
    keys := re.SubexpNames()
    
    // create map
    d := make(map[string]string)
    for i := 1; i < len(keys); i++ {
        d[keys[i]] = values[i]
    }
    fmt.Println(d)
    // OUTPUT: map[time:2017-05-30T19:02:08-05:00 level:info]
    

    values 是一个包含所有子匹配的列表。第一个子匹配是匹配正则表达式的整个表达式,然后是每个捕获组的子匹配。

    如果您更频繁地需要,您可以将代码包装到一个函数中(即,如果您需要类似 pythons match.groupdict 的东西):

    package main
    
    import (
        "fmt"
        "regexp"
    )
    
    func groupmap(s string, r *regexp.Regexp) map[string]string {
        values := r.FindStringSubmatch(s)
        keys := r.SubexpNames()
    
        // create map
        d := make(map[string]string)
        for i := 1; i < len(keys); i++ {
            d[keys[i]] = values[i]
        }
    
        return d
    }
    
    func main() {
        s := `time="2017-05-30T19:02:08-05:00" level=info msg="some log message" app=sample size=10`
        re := regexp.MustCompile(`time="(?P<time>.*?)"\slevel=(?P<level>.*?)\s`)
    
        fmt.Println(groupmap(s, re))
        // OUTPUT: map[time:2017-05-30T19:02:08-05:00 level:info]
    }
    

    【讨论】:

      猜你喜欢
      • 2021-01-19
      • 1970-01-01
      • 1970-01-01
      • 2022-01-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多