Golang regular expression for parsing key value pair into a string map

huangapple go评论106阅读模式
英文:

Golang regular expression for parsing key value pair into a string map

问题

我正在寻找一种方法,使用正则表达式将以下字符串解析为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,但是无法找到合适的正则表达式。这是正确的方法吗?

英文:

I'm looking to parse the following string into a map[string]string using a regular expression:

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

I'm trying to create a map that would have

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

etc

I have tried using regex.FindAllStringIndex but can't quite come up with an appropriate regex? Is this the correct way to go?

答案1

得分: 5

这是一个示例,不使用正则表达式,而是使用strings.FieldsFunc来实现相同的功能。

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)
	}
}
英文:

This is not using regex but is just an example of how to achieve the same by using 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)
	}
}

答案2

得分: 4

你可以使用github.com/kr/logfmt来代替自己编写正则表达式。

该包实现了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
}
英文:

Instead of writing regex of your own, you could simply use the github.com/kr/logfmt package.

> Package implements the decoding of logfmt key-value pairs.
>
> Example logfmt message:
>
> foo=bar a=14 baz="hello kitty" cool%story=bro f %^asdf
>
> Example result in JSON:
>
> {
> "foo": "bar",
> "a": 14,
> "baz": "hello kitty",
> "cool%story": "bro",
> "f": true,
> "%^asdf": true
> }

答案3

得分: 2

使用命名捕获组和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=&quot;(?P<time>.*?)&quot;\slevel=(?P<level>.*?)\s`)
values := re.FindStringSubmatch(s)
keys := re.SubexpNames()

// 创建映射
d := make(map[string]string)
for i := 1; i < len(keys); i++ {
    d[keys[i]] = values[i]
}
fmt.Println(d)
// 输出: map[time:2017-05-30T19:02:08-05:00 level:info]

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

如果你需要经常使用这个功能(例如类似Python的match.groupdict),你可以将代码封装成一个函数:

package main

import (
    "fmt"
    "regexp"
)

func groupmap(s string, r *regexp.Regexp) map[string]string {
    values := r.FindStringSubmatch(s)
    keys := r.SubexpNames()

    // 创建映射
    d := make(map[string]string)
    for i := 1; i < len(keys); i++ {
        d[keys[i]] = values[i]
    }

    return d
}

func main() {
    s := `time=&quot;2017-05-30T19:02:08-05:00&quot; level=info msg=&quot;some log message&quot; app=sample size=10`
    re := regexp.MustCompile(`time=&quot;(?P<time>.*?)&quot;\slevel=(?P<level>.*?)\s`)

    fmt.Println(groupmap(s, re))
    // 输出: map[time:2017-05-30T19:02:08-05:00 level:info]
}

希望对你有帮助!

英文:

Use named capturing groups in your regular expression and the FindStringSubmatch and SubexpNames functions. E.g.:

s := `time=&quot;2017-05-30T19:02:08-05:00&quot; level=info msg=&quot;some log message&quot; app=sample size=10`
re := regexp.MustCompile(`time=&quot;(?P&lt;time&gt;.*?)&quot;\slevel=(?P&lt;level&gt;.*?)\s`)
values := re.FindStringSubmatch(s)
keys := re.SubexpNames()

// create map
d := make(map[string]string)
for i := 1; i &lt; len(keys); i++ {
	d[keys[i]] = values[i]
}
fmt.Println(d)
// OUTPUT: map[time:2017-05-30T19:02:08-05:00 level:info]

values is a list containing all submatches. The first submatch is the whole expression that matches the regexp, followed by a submatch for each capturing group.

You can wrap the code into a function if you need this more frequently (i.e. if you need something like pythons match.groupdict):

package main

import (
    &quot;fmt&quot;
	&quot;regexp&quot;
)

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 &lt; len(keys); i++ {
    	d[keys[i]] = values[i]
    }

    return d
}

func main() {
    s := `time=&quot;2017-05-30T19:02:08-05:00&quot; level=info msg=&quot;some log message&quot; app=sample size=10`
    re := regexp.MustCompile(`time=&quot;(?P&lt;time&gt;.*?)&quot;\slevel=(?P&lt;level&gt;.*?)\s`)

    fmt.Println(groupmap(s, re))
    // OUTPUT: map[time:2017-05-30T19:02:08-05:00 level:info]
}

huangapple
  • 本文由 发表于 2017年5月31日 14:27:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/44277222.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定