golang正则之命名分组方式


Posted in Golang onApril 25, 2021

正则中有分组这个功能,在golang中也可以使用命名分组。

一次匹配的情况

场景还原如下:

有一行文本,格式为:姓名 年龄 邮箱地址

请将其转换为一个map

代码实现如下:

str := `Alice 20 alice@gmail.com`
// 使用命名分组,显得更清晰
re := regexp.MustCompile(`(?P<name>[a-zA-Z]+)\s+(?P<age>\d+)\s+(?P<email>\w+@\w+(?:\.\w+)+)`)
match := re.FindStringSubmatch(str)
groupNames := re.SubexpNames()
fmt.Printf("%v, %v, %d, %d\n", match, groupNames, len(match), len(groupNames))
result := make(map[string]string)
// 转换为map
for i, name := range groupNames {
    if i != 0 && name != "" { // 第一个分组为空(也就是整个匹配)
        result[name] = match[i]
    }
}
prettyResult, _ := json.MarshalIndent(result, "", "  ")
fmt.Printf("%s\n", prettyResult)

输出为:

[Alice 20 alice@gmail.com Alice 20 alice@gmail.com], [ name age email], 4, 4
{
  "age": "20",
  "email": "alice@gmail.com",
  "name": "Alice"
}

注意 [ name age email]有4个元素, 第一个为""。

多次匹配的情况

接上面的例子,实现一个更贴近现实的需求:

有一个文件, 内容大致如下:

Alice 20 alice@gmail.com
Bob 25 bob@outlook.com
gerrylon 26 gerrylon@github.com
...
更多内容

和上面一样, 不过这次转出来是一个slice of map, 也就是多个map。

代码如下:

// 文件内容直接用字符串表示
usersStr := `
    Alice 20 alice@gmail.com
    Bob 25 bob@outlook.com
    gerrylon 26 gerrylon@github.com
`
userRe := regexp.MustCompile(`(?P<name>[a-zA-Z]+)\s+(?P<age>\d+)\s+(?P<email>\w+@\w+(?:\.\w+)+)`)
// 这里要用FindAllStringSubmatch,找到所有的匹配
users := userRe.FindAllStringSubmatch(usersStr, -1)
groupNames := userRe.SubexpNames()
var result []map[string]string // slice of map
// 循环所有行
for _, user := range users {
    m := make(map[string]string)
    // 对每一行生成一个map
    for j, name := range groupNames {
        if j != 0 && name != "" {
            m[name] = strings.TrimSpace(user[j])
        }
    }
    result = append(result, m)
}
prettyResult, _ := json.MarshalIndent(result, "", "  ")
fmt.Println(string(prettyResult))

输出为:

[
  {
    "age": "20",
    "email": "alice@gmail.com",
    "name": "Alice"
  },
  {
    "age": "25",
    "email": "bob@outlook.com",
    "name": "Bob"
  },
  {
    "age": "26",
    "email": "gerrylon@github.com",
    "name": "gerrylon"
  }
]

总结

使用命名分组可以使正则表示的意义更清晰。

转换为map更加符合人类的阅读习惯,不过比一般的根据索引取分组值麻烦一些。

补充:golang 正则分组匹配多个值

看代码吧~

import (
   "encoding/json"
   "fmt"
   "regexp"
)
str := `9x_xx:995:88`  // `9x_xx:995`
// 使用命名分组,一次匹配多个值
re := regexp.MustCompile(`(?P<fname>\w+):+(?P<mod>[1-9]*):*(?P<strlen>[0-9]*)`)
match := re.FindStringSubmatch(str)
groupNames := re.SubexpNames()
fmt.Printf("%v, %v, %d, %d\n", match, groupNames, len(match), len(groupNames))
 
result := make(map[string]string)
if len(match) == len(groupNames) {
   // 转换为map
   for i, name := range groupNames {
      if i != 0 && name != "" { // 第一个分组为空(也就是整个匹配)
         result[name] = match[i]
      }
   }
}
prettyResult, _ := json.MarshalIndent(result, "", "  ") 
fmt.Printf("%s\n", prettyResult)

以上为个人经验,希望能给大家一个参考,也希望大家多多支持三水点靠木。如有错误或未考虑完全的地方,望不吝赐教。

Golang 相关文章推荐
golang在GRPC中设置client的超时时间
Apr 27 Golang
Golang 空map和未初始化map的注意事项说明
Apr 29 Golang
聊聊golang中多个defer的执行顺序
May 08 Golang
Go语言实现Snowflake雪花算法
Jun 08 Golang
Go 通过结构struct实现接口interface的问题
Oct 05 Golang
Golang数据类型和相互转换
Apr 12 Golang
golang使用map实现去除重复数组
Apr 14 Golang
Golang jwt身份认证
Apr 20 Golang
Golang 结构体数据集合
Apr 22 Golang
GoFrame gredis缓存DoVar Conn连接对象 自动序列化GoFrame gredisDo/DoVar方法Conn连接对象自动序列化/反序列化总结
Jun 14 Golang
Go gRPC进阶教程gRPC转换HTTP
Jun 16 Golang
GoFrame基于性能测试得知grpool使用场景
Jun 21 Golang
go语言-在mac下brew升级golang
Apr 25 #Golang
go原生库的中bytes.Buffer用法
Apr 25 #Golang
Go缓冲channel和非缓冲channel的区别说明
Apr 25 #Golang
Go语言使用select{}阻塞main函数介绍
win10下go mod配置方式
Go语言-为什么返回值为接口类型,却返回结构体
Apr 24 #Golang
go:垃圾回收GC触发条件详解
Apr 24 #Golang
You might like
编译问题
2006/10/09 PHP
Ajax PHP简单入门教程代码
2008/04/25 PHP
PHP实现指定字段的多维数组排序函数分享
2015/03/09 PHP
Yii框架结合sphinx,Ajax实现搜索分页功能示例
2016/10/18 PHP
php版微信自定义回复功能示例
2016/12/05 PHP
PHP基于DOMDocument解析和生成xml的方法分析
2017/07/17 PHP
javascript+css 网页每次加载不同样式的实现方法
2009/12/27 Javascript
Jqgrid表格随窗口大小改变而改变的简单实例
2013/12/28 Javascript
ExtJS如何设置与获取radio控件的选取状态
2014/01/22 Javascript
jquery和js实现对div的隐藏和显示方法
2014/09/26 Javascript
使用jquery动态加载js文件的方法
2014/12/24 Javascript
jQuery功能函数详解
2015/02/01 Javascript
jQuery支持添加事件的日历特效代码分享(3种样式)
2015/08/24 Javascript
jquery获取img的src值的简单实例
2016/05/17 Javascript
vuex实现简易计数器
2016/10/27 Javascript
Angular实现的进度条功能示例
2018/02/18 Javascript
vue.js获得当前元素的文字信息方法
2018/03/09 Javascript
浅谈Vue 性能优化之深挖数组
2018/12/11 Javascript
vue router 组件的高级应用实例代码
2019/04/08 Javascript
使用nodejs分离html文件里的js和css详解
2019/04/12 NodeJs
微信小程序swiper使用网络图片不显示问题解决
2019/12/13 Javascript
vue图片裁剪插件vue-cropper使用方法详解
2020/12/16 Vue.js
[03:53]2016国际邀请赛中国区预选赛第三日TOP10精彩集锦
2016/06/29 DOTA
[01:22:28]DOTA2-DPC中国联赛 正赛 SAG vs RNG BO3 第一场 1月18日
2021/03/11 DOTA
python matplotlib绘制三维图的示例
2020/09/24 Python
Python+OpenCV图像处理——打印图片属性、设置存储路径、调用摄像头
2020/10/22 Python
python爬取豆瓣电影排行榜(requests)的示例代码
2021/02/18 Python
AmazeUI 折叠面板的实现代码
2020/08/17 HTML / CSS
台湾最大银发乐活百货:乐龄网
2018/05/21 全球购物
Deichmann英国:德国鞋类零售商
2021/01/30 全球购物
main 主函数执行完毕后,是否可能会再执行一段代码,给出说明
2012/12/05 面试题
说明书怎么写
2014/05/06 职场文书
监察建议书格式
2014/05/19 职场文书
竞聘上岗演讲
2014/05/19 职场文书
红色故事演讲稿
2014/05/22 职场文书
2015年六一儿童节活动方案
2015/05/05 职场文书