扫二维码与项目经理沟通
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流
正则中有分组这个功能,在golang中也可以使用命名分组。
万年网站制作公司哪家好,找创新互联!从网页设计、网站建设、微信开发、APP开发、响应式网站设计等网站项目制作,到程序开发,运营维护。创新互联从2013年成立到现在10年的时间,我们拥有了丰富的建站经验和运维经验,来保证我们的工作的顺利进行。专注于网站建设就选创新互联。
一次匹配的情况
场景还原如下:
有一行文本,格式为:姓名 年龄 邮箱地址
请将其转换为一个map
代码实现如下:
str := `Alice 20 alice@gmail.com`
// 使用命名分组,显得更清晰
re := regexp.MustCompile(`(?Pname[a-zA-Z]+)\s+(?Page\d+)\s+(?Pemail\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(`(?Pname[a-zA-Z]+)\s+(?Page\d+)\s+(?Pemail\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"
}
]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
总结
使用命名分组可以使正则表示的意义更清晰。
转换为map更加符合人类的阅读习惯,不过比一般的根据索引取分组值麻烦一些。
————————————————
版权声明:本文为CSDN博主「butterfly5211314」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:
1. PHP 邮箱验证正则表达式:
preg_match("/^[0-9a-zA-Z]+@(([0-9a-zA-Z]+)[.])+[a-z]{2,4}$/i",$email );
如果需要更加完善、严格的验证,修改这个正则表达式即可。
2. PHP 邮箱验证正则表达式实例:
?php
function isEmail($email){
if(preg_match("/^[0-9a-zA-Z]+@(([0-9a-zA-Z]+)[.])+[a-z]{2,4}$/i",$email )){
return '是邮箱';
} else{
return '不是邮箱';
}
}
?
3. Javascript(js) 邮箱验证正则表达式:
myreg = /^([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+@([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+\.[a-zA-Z]{2,4}$/;
这个可以验证 形如:i@julying.com ,i@i.com 这种邮箱
4. Javascript(js) 邮箱验证正则表达式实例:
script type="text/javascript"
function isEmail(val){
var myreg = /^([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+@([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+\.[a-zA-Z]{2,4}$/;
if(!myreg.test(val))
return '不是邮箱';
return '是邮箱';
};
alert( isEmail('i@julying.com') );
/script
虽然没有统一的邮箱账号格式,但是所有邮箱都符合“名称@域名”的规律。对于名称和域名的字符限制,我们可以根据项目的情况定义一个,比如只允许有英文、数字、下划线等组成。下面举例实现一些验证邮箱格式的正则表达式。
实例1:只允许英文字母、数字、下划线、英文句号、以及中划线组成
举例:sunxiuzhen@dctc.org.cn
分析邮件名称部分:
26个大小写英文字母表示为a-zA-Z
数字表示为0-9
下划线表示为_
中划线表示为-
由于名称是由若干个字母、数字、下划线和中划线组成,所以需要用到+表示多次出现,根据以上条件得出邮件名称表达式:[a-zA-Z0-9_-]+
分析域名部分:一般域名的规律为“[N级域名][三级域名.]二级域名.顶级域名”,比如“qq.com”、“”、“mp.weixin.qq.com”、“12-34.com.cn”,分析可得域名类似“** .** .**.**”组成。
“**”部分可以表示为[a-zA-Z0-9_-]+
“.**”部分可以表示为\.[a-zA-Z0-9_-]+
多个“.**”可以表示为(\.[a-zA-Z0-9_-]+)+
综上所述,域名部分可以表示为[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+
最终表达式: 由于邮箱的基本格式为“名称@域名”,需要使用“^”匹配邮箱的开始部分,用“$”匹配邮箱结束部分以保证邮箱前后不能有其他字符,所以最终邮箱的正则表达式为:
^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$
实例2:名称允许汉字、字母、数字,域名只允许英文域名
举例:张三001Abc@lenovo.com.cn
分析邮件名称部分:
汉字在正则表示为[\u4e00-\u9fa5]
字母和数字表示为A-Za-z0-9
通过分析得出邮件名称部分表达式为[A-Za-z0-9\u4e00-\u9fa5]+
分析邮件域名部分:邮件部分可以参考实例1中的分析域名部分。
得出域名部分的表达式为[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+。
最终表达式: 我们用@符号将邮箱的名称和域名拼接起来,因此完整的邮箱表达式为 :
^[A-Za-z0-9\u4e00-\u9fa5]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$
维基百科中反射的定义:在计算机科学中,反射是指计算机程序在运行时(Run time)可以访问、检测和修改它本身状态或行为的一种能力。用比喻来说,反射就是程序在运行的时候能够“观察”并且修改自己的行为。
golang reflect包实现了反射。动态的获得程序运行时对象的结构和信息。
reflect 包中提供了两个基础的关于反射的函数来获取上述的接口和结构体:
func TypeOf(i interface{}) Type
func ValueOf(i interface{}) Value
大体上可以这样理解,TypeOf获取对象的类型信息,ValueOf获取对象中存储的值。
golang tag
golang中可以为结构体的字段添加tag。golang本身的encoding/json包解析json使用了tag,一些开源的orm框架如gorm,也使用了tag。tag可以方便的为结构体的字段添加一些信息,用reflect可以读取到,加以利用。
这是一个用tag标记列名以实现结构体自动生成xlsx的例子:
```
type Employee struct{
ID int `xlsx:”工号”`
Name string `xlsx:”姓名”`
Email string `xlsx:”邮箱”`
}
func Outputxlsx(es []*Employee) ([]byte, error) {
xt := reflect.TypeOf(es[0])
xv := reflect.ValueOf(es[0])
rows := [][]interface{}{}
headers := []interface{}{}
for i := 0; i xt.Elem().NumField(); i++ {
head, ok := xt.Elem().Field(i).Tag.Lookup("xlsx")
if ok {
headers = append(headers, head)
}
}
for _, e := range es {
cells := []interface{}{}
xv := reflect.ValueOf(e)
for i := 0; i xv.Elem().NumField(); i++ {
_, ok := xt.Elem().Field(i).Tag.Lookup("xlsx")
if ok {
cells = append(cells, xv.Elem().Field(i).Interface())
}
}
rows = append(rows, cells)
}
file := xlsx.NewFile()
sheet, _ := file.AddSheet("sheet1")
row := sheet.AddRow()
for _, header := range headers {
row.AddCell().Value = fmt.Sprintf("%v", header)
}
for _, v := range rows {
row := sheet.AddRow()
for _, vv := range v {
row.AddCell().Value = fmt.Sprintf("%v", vv)
}
}
var buffer bytes.Buffer
if err := file.Write(buffer); err != nil {
return nil, err
}
return buffer.Bytes(), nil
}
```
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流