如何编写可处理任意顺序多个key=value键值对的正则表达式
适配任意顺序键值对的正则实现方案
核心思路
Go标准库的regexp采用RE2引擎,我们可以将每个需要提取的键值对封装为独立的可选匹配分组,配合惰性匹配跳过无关内容,即可完全不依赖键的出现顺序完成提取。
修正后的正则规则
针对你需要提取的datetime、event、duration三个字段,正则写法如下:
^.*?(?:datetime="(?P<datetime>[^"]*)")?.*?(?:event="(?P<event>[^"]*)")?.*?(?:duration=(?P<duration>\S+))?.*$
规则说明
- 每个目标键对应一个可选非捕获组
(?:匹配规则)?,字段存在就提取值,不存在也不会导致整体匹配失败 .*?为惰性匹配,用于跳过当前字段前的任意无关内容,无需关注字段出现顺序- 用
[^"]*匹配双引号包裹的值,比惰性匹配.*?性能更高,也不会出现越界匹配问题 - 用
\S+匹配无引号的纯数值/纯文本值,匹配到空白字符自动停止
完整可运行代码
package main import ( "fmt" "regexp" ) // groupmap 将正则匹配结果转为命名分组的map 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() { input := `extra_data_probably_has_equal_sign_in_it datetime="2021-05-30T11:02:00-09:00" level=info event="event content" duration=0` // 顺序无关的正则 re := regexp.MustCompile(`^.*?(?:datetime="(?P<datetime>[^"]*)")?.*?(?:event="(?P<event>[^"]*)")?.*?(?:duration=(?P<duration>\S+))?.*$`) fmt.Println(groupmap(input, re)) }
运行输出:
map[datetime:2021-05-30T11:02:00-09:00 duration:0 event:event content]
扩展说明
如果需要新增提取字段,只需要按照.*?(?:键规则(?P<键名>值规则))?的格式插入正则即可,不需要调整现有匹配逻辑,比如要新增提取level字段,修改正则为:
^.*?(?:datetime="(?P<datetime>[^"]*)")?.*?(?:event="(?P<event>[^"]*)")?.*?(?:duration=(?P<duration>\S+))?.*?(?:level=(?P<level>\S+))?.*$
内容的提问来源于stack exchange,提问作者Haifeng Zhang
相关产品推荐
相关产品推荐

