高级
分组
有时你想匹配一段文本,但只想提取出部分的内容。 在之前的正则表达式基础中,我们都是匹配整个文本
re, err := regexp.Compile(`.at`)
res := re.FindAllStringSubmatch("The cat sat on the mat.", -1)
fmt.Printf("%v", res) //[[cat] [sat] [mat]]
() 允许捕获分字符块,而不是整个表达式
re, err := regexp.Compile(`(.)at`) // want to know what is in front of 'at'
res := re.FindAllStringSubmatch("The cat sat on the mat.", -1)
fmt.Printf("%v", res) //[[cat c] [sat s] [mat m]]
你也可以指定多个()分组
// Prints [[ex e x] [ec e c] [e e ]]
s := "Nobody expects the Spanish inquisition."
re1, err := regexp.Compile(`(e)(.)`) // Prepare our regex
result_slice := re1.FindAllStringSubmatch(s, -1)
fmt.Printf("%v", result_slice)
FindAllStringSubmatch()函数, 对于每一次匹配, 返回一个数组,第一字段是整个匹配到的字符串,之后的则是()中的分组内容。
如果你有一个可选的分组,而它又没有出现在字符串中, 则返回的数组会在此位置有一个空字符串, 换句语说,返回的数组长度等于正则表达式中()的数量加1。
s := "Mr. Leonard Spock"
re1, err := regexp.Compile(`(Mr)(s)?\. (\w+) (\w+)`)
result:= re1.FindStringSubmatch(s)
for k, v := range result {
fmt.Printf("%d. %s\n", k, v)
}
// Prints
// 0. Mr. Leonard Spock
// 1. Mr
// 2.
// 3. Leonard
// 4. Spock
对匹配项进行命名
依次将匹配项保存到一个数组中,会出现以下两个问题 。
- 当你要正则表达式插入一个新的分组. 在此之后的index,都会加1。
- 字符串可能是在运行时构造,可能包含多个()
re := regexp.MustCompile("(?P<first_char>.)(?P<middle_part>.*)(?P<last_char>.)")
n1 := re.SubexpNames()
r2 := re.FindAllStringSubmatch("Super", -1)[0]
fmt.Println(n1)
fmt.Println(r2)
md := map[string]string{}
for i, n := range r2 {
fmt.Printf("%d. match='%s'\tname='%s'\n", i, n, n1[i])
md[n1[i]] = n
}
fmt.Printf("The names are : %v\n", n1)
fmt.Printf("The matches are: %v\n", r2)
fmt.Printf("The first character is %s\n", md["first_char"])
fmt.Printf("The last character is %s\n", md["last_char"])
Output
[ first_char middle_part last_char] //index 0 为 ''
[Super S upe r]
0. match='Super' name=''
1. match='S' name='first_char'
2. match='upe' name='middle_part'
3. match='r' name='last_char'
The names are : [ first_char middle_part last_char]
The matches are: [Super S upe r]
The first character is S
The last character is r
高级重复
非捕获重复
如果()只是用来分组,进行重复,而不想被捕获。 可以使用(?:regex)。 以下是捕获所用分组的用法
s := "Mrs. Leonora Spock"
re1, err := regexp.Compile(`Mr(s)?\. (\w+) (\w+)`)
result:= re1.FindStringSubmatch(s)
for k, v := range result {
fmt.Printf("%d. %s\n", k, v)
}
// 0. Mrs. Leonora Spock
// 1. s
// 2. Leonora
// 3. Spock
非捕获分组
s := "Mrs. Leonora Spock"
re1, err := regexp.Compile(`Mr(?:s)?\. (\w+) (\w+)`)
result:= re1.FindStringSubmatch(s)
for k, v := range result {
fmt.Printf("%d. %s\n", k, v)
}
// 0. Mrs. Leonora Spock
// 1. Leonora
// 2. Spock
指定重复次数
s := "11110010101111100101001001110101"
re1, err := regexp.Compile(`1{4}`)
res := re1.FindAllStringSubmatch(s,-1)
fmt.Printf("<%v>", res)
// <[[1111] [1111]]>
res2 := re1.FindAllStringIndex(s,-1)
fmt.Printf("<%v>", res2)
// <[[0 4] [10 14]]>
{}的语法很少使用。一个原因是你可以用一种简单的方式来重写表达式。
(ab){3} == (ababab)
(ab){3,4} == (ababab(ab)??)
??表示0个或者1个,但更喜欢0个
标志
正则表达式可以使用以下标志
- i 忽略大小写(默认false)
- m 多行模式:^ 和 $ 匹配每行的begin/end,而不是整个文本的begin/end (default false)
- s 让 .匹配\n (default false)
- U 非贪婪模式: x* -> x*?, x+ -> x+? (default false)
忽略大小写
s := "Never say never."
r, err := regexp.Compile(`(?i)^n`) // Do we have an 'N' or 'n' at the beginning?
fmt.Printf("%v", r.MatchString(s)) // true, case insensitive
在正则的开发中,很少使用到正则表达式的忽略大小写匹配。 通常我们是将整个表达式统一为大小或者小写之后在进行匹配
sMixed := "Never say never."
sLower := strings.ToLower(sMixed) // don't forget to import "strings"
r, err := regexp.Compile(`^n`)
fmt.Printf("%v ", r.MatchString(sMixed)) // false, N != n
fmt.Printf("%v ", r.MatchString(sLower)) // true, n == n
贪婪与非贪婪
r, err := regexp.Compile(`'.*'`)
res := r.FindString(" 'abc','def','ghi' ")
fmt.Printf("<%v>", res)
// Will print: <'abc','def','ghi'>
你可以使用非贪婪模式,只匹配'abc'
r, err := regexp.Compile(`'.*?'`)
res := r.FindString(" 'abc','def','ghi' ")
fmt.Printf("<%v>", res)
// Will print: <'abc'>
你也可以使用U flag
r, err := regexp.Compile(`(?U)'.*'`)
res := r.FindString(" 'abc','def','ghi' ")
fmt.Printf("<%v>", res)
// Will print: <'abc'>
Dot(.) 可以匹配\n
当你有一个多行的字符串(一个字符串中包含'\n')。你可以使用(?s) flag, 让 '.'可以匹配\n. 默认为false,如下
r, err := regexp.Compile(`a.`)
s := "atlanta\narkansas\nalabama\narachnophobia"
res := r.FindAllString(s, -1)
fmt.Printf("<%v>", res)
// <[at an ar an as al ab am ar ac]>
使用(?s) flag
r, err := regexp.Compile(`(?s)a.`)
s := "atlanta\narkansas\nalabama\narachnophobia"
res := r.FindAllString(s, -1)
fmt.Printf("<%v>", res)
// Prints
// <[at an a
// ar an as al ab am a
// ar ac]>
^/$ 匹配新行
r, err1 := regexp.Compile(`a$`) // without flag
s := "atlanta\narkansas\nalabama\narachnophobia"
// 01234567 890123456 78901234 5678901234567
// -
res := r.FindAllStringIndex(s,-1)
fmt.Printf("<%v>\n", res)
// 1 match
// <[[37 38]]>
t, err2 := regexp.Compile(`(?m)a$`) // with flag
u := "atlanta\narkansas\nalabama\narachnophobia"
// 01234567 890123456 78901234 5678901234567
// -- -- -
res2 := t.FindAllStringIndex(u,-1)
fmt.Printf("<%v>", res2)
// 3 matches
// <[[6 7] [23 24] [37 38]]>