submatch的使用,首先要在规则表达式里面使用grouping’()‘
标识出来。
举一个例子:
re := regexp.MustCompile(`a(x*)b`)
fmt.Printf("%q\n", re.FindStringSubmatch("-axxxb-"))
// ["axxxb" "xxx"]
fmt.Printf("%q\n", re.FindStringSubmatch("-axb-"))
["axb" "x"]
fmt.Printf("%q\n", re.FindStringSubmatch("-ab-"))
["axb" "x"]
这里a(x*)b
是一个待匹配的规则表达式,其中的(x*)
就是submatch。当整个字符串匹配满足规则表达式时,同时就会把对应的submatch也匹配出来。
当然submatch可以有多个,按定义的先后顺序排列。
submatch特别有用的一个地方是提取字符串:
- 先判断字符串是否满足给定的规则表达式;
- 如果满足,则把其中的一部分提取出来。
在前面的例子中:
- 首先判断字符串是否满足字母
a
和b
中间包含0个或者多个x
的格式。 - 如果是,则把其中的所有
x
提取出来。 - 进一步,可以把这些不确定个数的
x
全部替换成其他字符。
如何放弃submatch
另外,之前我们知道括号也是用来分组用的,例如(ab)+
和格式ab+
的区分,这个时候虽然用了括号分组,但是有时并不需要这个submatch,只是控制语法的需要。
语法(?:re)
就用来放弃这个submatch的功能。
还是举个例子来说更清楚:
re1 := regexp.MustCompile(`a(x*)b(y+)c`)
fmt.Printf("%q\n", re1.FindStringSubmatch("-axxxbyyc-"))
// ["axxxbyyc" "xxx" "yy"]
fmt.Printf("%q\n", re1.FindStringSubmatch("-axbyc-"))
// ["axbyc" "x" "y"]
fmt.Printf("%q\n", re1.FindStringSubmatch("-abc-"))
// []
re2 := regexp.MustCompile(`a(?:x*)b(y+)c`)
fmt.Printf("%q\n", re2.FindStringSubmatch("-axxxbyyc-"))
// ["axxxbyyc" "yy"]
fmt.Printf("%q\n", re2.FindStringSubmatch("-axbyc-"))
// ["axbyc" "y"]
fmt.Printf("%q\n", re2.FindStringSubmatch("-abc-"))
// []
其中group '(x*)'
在re1里是一个submatch,而在re2里面不是一个submatch;虽然re1和re2的规则表达式匹配的规则是一样的,但是在结果输出中,这个group并没有被包含再re2的输出中。
如何用命名来约取submatch
还是以前面例子为例:
re := regexp.MustCompile(`a(x*)b(y+)c`)
matches := re.FindStringSubmatch("-axxxbyyc-")
fmt.Printf("%q\n", matches) // ["axxxbyyc" "xxx" "yy"]
fmt.Printf("%q\n", matches[0]) // "axxxbyyc"
fmt.Printf("%q\n", matches[1]) // "xxx"
fmt.Printf("%q\n", matches[2]) // "yyy"
可以通过matches[index]下标来获取对应的submatch,而golang如果submatch很多的话,而且将来一旦调整修改,下标可能会发生变化,所以golang规则表达式同样支持命名的方式,这样就可以使得代码相对固定。
命名submatch的格式是:(?P<name>re)
同样的例子:
re := regexp.MustCompile(`a(?P<match1>x*)b(?P<match2>y+)c`)
matches := re.FindStringSubmatch("-axxxbyyc-")
match1Index := re.SubexpIndex("match1")
match2Index := re.SubexpIndex("match2")
fmt.Printf("matches[%d]=%q\n", match1Index, matches[match1Index]) // "xxx"
fmt.Printf("matches[%d]=%q\n", match2Index, matches[match2Index]) // "yy"
这样不管以后regular expression pattern 怎么变化,只要名字match1/match2没有发生变化,最终的输出结果都是一致的。
需要注意的是:
- index下标从1开始,因为下标0已经分配给了整个匹配串。
- 自己要负责保证naming不会重复哈,不然只有第一个有效了(测试结果)。
网友评论