2017-05-31 15 views
1

我期待使用正则表达式来解析以下字符串成map[string]stringGolang正则表达式解析键值对成字符串映射

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尝试,但不能完全拿出一个合适的正则表达式?这是正确的方法吗?

+2

使用一个真正的解析器来代替。 – Jan

+0

[RegEx匹配开放标签,但XHTML自包含标签除外]的可能重复(https://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags) – Jan

回答

2

这是不使用正则表达式,但仅仅是如何实现的例子同样使用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) 
    } 
} 
+0

这是我最终使用了什么,但是@kennytm的解决方案同样很好,只要你有额外的依赖就可以了。 – Xeaz

3

您可以简单地使用github.com/kr/logfmt package来代替编写自己的正则表达式。

包实现logfmt键 - 值对的解码。

例logfmt消息:

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

例结果JSON:

命名为正则表达式和FindStringSubmatch和SubexpNames功能捕获组
{ 
    "foo": "bar", 
    "a": 14, 
    "baz": "hello kitty", 
    "cool%story": "bro", 
    "f": true, 
    "%^asdf": true 
} 
0

使用。例如:

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是包含所有子匹配的列表。第一个子匹配是与正则表达式匹配的整个表达式,然后是每个捕获组的子匹配。

你可以用代码到一个功能,如果你需要这个更频繁地(例如,如果你需要像蟒蛇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] 
}