diff --git a/zh/07.3.md b/zh/07.3.md index db55d633..74df4f1b 100644 --- a/zh/07.3.md +++ b/zh/07.3.md @@ -9,14 +9,17 @@ Go语言通过`regexp`标准包为正则表达式提供了官方支持,如果 ## 通过正则判断是否匹配 `regexp`包中含有三个函数用来判断是否匹配,如果匹配返回true,否则返回false +```Go func Match(pattern string, b []byte) (matched bool, error error) func MatchReader(pattern string, r io.RuneReader) (matched bool, error error) func MatchString(pattern string, s string) (matched bool, error error) +``` 上面的三个函数实现了同一个功能,就是判断`pattern`是否和输入源匹配,匹配的话就返回true,如果解析正则出错则返回error。三个函数的输入源分别是byte slice、RuneReader和string。 如果要验证一个输入是不是IP地址,那么如何来判断呢?请看如下实现 +```Go func IsIP(ip string) (b bool) { if m, _ := regexp.MatchString("^[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}$", ip); !m { @@ -24,8 +27,9 @@ Go语言通过`regexp`标准包为正则表达式提供了官方支持,如果 } return true } - +``` 可以看到,`regexp`的pattern和我们平常使用的正则一模一样。再来看一个例子:当用户输入一个字符串,我们想知道是不是一次合法的输入: +```Go func main() { if len(os.Args) == 1 { @@ -37,13 +41,14 @@ Go语言通过`regexp`标准包为正则表达式提供了官方支持,如果 fmt.Println("不是数字") } } - +``` 在上面的两个小例子中,我们采用了Match(Reader|String)来判断一些字符串是否符合我们的描述需求,它们使用起来非常方便。 ## 通过正则获取内容 Match模式只能用来对字符串的判断,而无法截取字符串的一部分、过滤字符串、或者提取出符合条件的一批字符串。如果想要满足这些需求,那就需要使用正则表达式的复杂模式。 我们经常需要一些爬虫程序,下面就以爬虫为例来说明如何使用正则来过滤或截取抓取到的数据: +```Go package main @@ -92,18 +97,21 @@ Match模式只能用来对字符串的判断,而无法截取字符串的一部 fmt.Println(strings.TrimSpace(src)) } +``` 从这个示例可以看出,使用复杂的正则首先是Compile,它会解析正则表达式是否合法,如果正确,那么就会返回一个Regexp,然后就可以利用返回的Regexp在任意的字符串上面执行需要的操作。 解析正则表达式的有如下几个方法: +```Go func Compile(expr string) (*Regexp, error) func CompilePOSIX(expr string) (*Regexp, error) func MustCompile(str string) *Regexp func MustCompilePOSIX(str string) *Regexp - +``` CompilePOSIX和Compile的不同点在于POSIX必须使用POSIX语法,它使用最左最长方式搜索,而Compile是采用的则只采用最左方式搜索(例如[a-z]{2,4}这样一个正则表达式,应用于"aa09aaa88aaaa"这个文本串时,CompilePOSIX返回了aaaa,而Compile的返回的是aa)。前缀有Must的函数表示,在解析正则语法的时候,如果匹配模式串不满足正确的语法则直接panic,而不加Must的则只是返回错误。 在了解了如何新建一个Regexp之后,我们再来看一下这个struct提供了哪些方法来辅助我们操作字符串,首先我们来看下面这些用来搜索的函数: +```Go func (re *Regexp) Find(b []byte) []byte func (re *Regexp) FindAll(b []byte, n int) [][]byte @@ -123,8 +131,9 @@ CompilePOSIX和Compile的不同点在于POSIX必须使用POSIX语法,它使用 func (re *Regexp) FindStringSubmatchIndex(s string) []int func (re *Regexp) FindSubmatch(b []byte) [][]byte func (re *Regexp) FindSubmatchIndex(b []byte) []int - +``` 上面这18个函数我们根据输入源(byte slice、string和io.RuneReader)不同还可以继续简化成如下几个,其他的只是输入源不一样,其他功能基本是一样的: +```Go func (re *Regexp) Find(b []byte) []byte func (re *Regexp) FindAll(b []byte, n int) [][]byte @@ -134,8 +143,9 @@ CompilePOSIX和Compile的不同点在于POSIX必须使用POSIX语法,它使用 func (re *Regexp) FindIndex(b []byte) (loc []int) func (re *Regexp) FindSubmatch(b []byte) [][]byte func (re *Regexp) FindSubmatchIndex(b []byte) []int - +``` 对于这些函数的使用我们来看下面这个例子 +```Go package main @@ -189,14 +199,16 @@ CompilePOSIX和Compile的不同点在于POSIX必须使用POSIX语法,它使用 submatchallindex := re2.FindAllSubmatchIndex([]byte(a), -1) fmt.Println(submatchallindex) } - +``` 前面介绍过匹配函数,Regexp也定义了三个函数,它们和同名的外部函数功能一模一样,其实外部函数就是调用了这Regexp的三个函数来实现的: +```Go func (re *Regexp) Match(b []byte) bool func (re *Regexp) MatchReader(r io.RuneReader) bool func (re *Regexp) MatchString(s string) bool - +``` 接下里让我们来了解替换函数是怎么操作的? +```Go func (re *Regexp) ReplaceAll(src, repl []byte) []byte func (re *Regexp) ReplaceAllFunc(src []byte, repl func([]byte) []byte) []byte @@ -204,15 +216,17 @@ CompilePOSIX和Compile的不同点在于POSIX必须使用POSIX语法,它使用 func (re *Regexp) ReplaceAllLiteralString(src, repl string) string func (re *Regexp) ReplaceAllString(src, repl string) string func (re *Regexp) ReplaceAllStringFunc(src string, repl func(string) string) string - +``` 这些替换函数我们在上面的抓网页的例子有详细应用示例, 接下来我们看一下Expand的解释: +```Go func (re *Regexp) Expand(dst []byte, template []byte, src []byte, match []int) []byte func (re *Regexp) ExpandString(dst []byte, template string, src string, match []int) []byte - +``` 那么这个Expand到底用来干嘛的呢?请看下面的例子: +```Go func main() { src := []byte(` @@ -227,7 +241,7 @@ CompilePOSIX和Compile的不同点在于POSIX必须使用POSIX语法,它使用 } fmt.Println(string(res)) } - +``` 至此我们已经全部介绍完Go语言的`regexp`包,通过对它的主要函数介绍及演示,相信大家应该能够通过Go语言的正则包进行一些基本的正则的操作了。