这两天再看go的正则表达式的时候,看到关于unicode匹配的方式\p{Name}
不是很明白,所以就想写程序来尝试一下,因此而引出博文标题提到的一个误区。
首先还是先解释下\p{name}
到底是什么意思。
这里的{name}
指的是unicode的类型对象名称,具体可在RE2 syntax中查看。其中{Han}可以用来匹配中文字符,因此下了下面的程序来验证。
package main
import (
"fmt"
"regexp"
)
func main() {
re, err := regexp.Compile(`\p{Han}*`)
if err != nil {
fmt.Println(err)
return
}
s := "foo中文哦test"
fmt.Println(re.FindString(s))
}
出乎意料的是上面的程序输出的是空,而我希望的是输出中文哦
然后对上面的程序进行了修改
package main
import (
"fmt"
"regexp"
)
func main() {
s := "foo中文哦woqu"
re, err := regexp.Compile(`\p{Han}*`)
if err != nil {
fmt.Println(err)
return
}
fmt.Println("find:", re.FindString(s))
re, err = regexp.Compile(`\p{Han}+`)
if err != nil {
fmt.Println(err)
return
}
fmt.Println("find:", re.FindString(s))
re, err = regexp.Compile(`\p{Han}?`)
if err != nil {
fmt.Println(err)
return
}
fmt.Println("find:", re.FindString(s))
}
这段程序有如下输出:
find:
find: 中文哦
find:
这就让我疑惑了,因为从文档查看到
- x* zero or more x, prefer more
- x+ one or more x, prefer more
- x? zero or one x, prefer one
所以为什么不是按照如下输出的呢:
find: 中文哦
find: 中文哦
find: 中
后来通过提问和搜索,终于找到了原因,
原因正是因为*
和?
除了匹配尽可能多的字符,还有一个特点就是也会匹配zero x
,因为find
只会查找到第一个匹配的字符,因此在*
和?
的情况下,第一个匹配到的都是空字符串,而+因为至少匹配一个,所以其匹配到的是中文哦
我们可以通过findAllString来验证一下:
package main
import (
"fmt"
"regexp"
)
func main() {
s := "foo中文哦woqu"
re, err := regexp.Compile(`\p{Han}*`)
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("find: %q\n", re.FindAllString(s, -1))
re, err = regexp.Compile(`\p{Han}+`)
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("find: %q\n", re.FindAllString(s, -1))
re, err = regexp.Compile(`\p{Han}?`)
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("find: %q\n", re.FindAllString(s, -1))
}
这段程序输出了:
find: [“” “” “” “中文哦” “” “” “” “”]
find: [“中文哦”]
find: [“” “” “” “中” “文” “哦” “” “” “” “”]
正好验证了我的猜测。