正则表达式是一种进行模式匹配和文本操纵的复杂而又强大的工具。虽然正则表达式比纯粹的文本匹配效率低,但是它却更灵活。按照它的语法规则,随需构造出的匹配模式就能够从原始文本中筛选出几乎任何你想要得到的字符组合。如果你在Web开发中需要从一些文本数据源中获取数据,那么你只需要按照它的语法规则,随需构造出正确的模式字符串就能够从原数据源提取出有意义的文本信息。
Go语言通过regexp
标准包为正则表达式提供了官方支持,如果你已经使用过其他编程语言提供的正则相关功能,那么你应该对Go语言版本的不会太陌生,但是它们之间也有一些小的差异,因为Go实现的是RE2标准,除了\C,详细的语法描述参考:http://code.google.com/p/re2/wiki/Syntax
其实字符串处理我们可以使用strings
包来进行搜索(Contains、Index)、替换(Replace)和解析(Split、Join)等操作,但是这些都是简单的字符串操作,他们的搜索都是大小写敏感,而且固定的字符串,如果我们需要匹配可变的那种就没办法实现了,当然如果strings
包能解决你的问题,那么就尽量使用它来解决。因为他们足够简单、而且性能和可读性都会比正则好。
regexp包中含有三个函数判断是否匹配,若匹配返回true,否则为false
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和输出源([]byte,RuneReader,string)是否匹配
//IsIp 判断输出值是否为Ip地址格式(仅判断位数)
func IsIp(s string) bool {
ipPattern := "^[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}$"
m, err := regexp.MatchString(ipPattern, s)
myutils.CheckError(err, "Regexp error")
return m
}
//main.go
func main() {
ip1 := "127.0.0.1"
ip2 := "dada513123"
fmt.Println(ip1, " : ", regexpnote.IsIp(ip1))
fmt.Println(ip2, " : ", regexpnote.IsIp(ip2))
}
127.0.0.1 : true
dada513123 : false
func SimpleCrawler() {
//Send Get request
resp, err := http.Get("http://www.baidu.com")
myutils.CheckError(err, "Http Get Error")
//Close Resp body
defer resp.Body.Close()
//Read resp data
data, err := ioutil.ReadAll(resp.Body)
myutils.CheckError(err, "Read data error")
src := string(data)
log.Println("Response : ", src)
//将所有html标签转换至小写
reg, _ := regexp.Compile(`<[\S\s]+?>`)
src = reg.ReplaceAllStringFunc(src, strings.ToLower)
//去除style标签
reg, _ = regexp.Compile(`<style[\S\s]+?</style>`)
src = reg.ReplaceAllString(src, "")
//去除script标签
reg, _ = regexp.Compile(`<script[\s\S]+?</script>`)
src = reg.ReplaceAllString(src, "")
//去除所有尖括号内的HTML代码,并换成换行符
reg, _ = regexp.Compile(`<[\S\s]+?>`)
src = reg.ReplaceAllString(src, "\n")
//去除连续的换行符
reg, _ = regexp.Compile(`\s{2,}`)
src = reg.ReplaceAllString(src, "\n")
log.Println("Response : ", src)
myutils.WriteDataToFile("../resources/tmp/baidu.txt", src)
}
正则解析函数Compile()会解析正则表达式是否合法,若合法则返回Regexp类型变量
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语法(使用最左最长方式搜索)后者采用(最左方式搜索),例如:[a-z]{2,4}搜索"aa09aaa88aaaa"时,POSIX会返回aaaa,Compile返回aa
前缀为Must的函数,正则表达式不合法是直接panic,无Must前缀的会返回错误
Regexp类型下的搜索方法:
func (re *Regexp) Find(b []byte) []byte
func (re *Regexp) FindAll(b []byte, n int) [][]byte
func (re *Regexp) FindAllIndex(b []byte, n int) [][]int
func (re *Regexp) FindAllString(s string, n int) []string
func (re *Regexp) FindAllStringIndex(s string, n int) [][]int
func (re *Regexp) FindAllStringSubmatch(s string, n int) [][]string
func (re *Regexp) FindAllStringSubmatchIndex(s string, n int) [][]int
func (re *Regexp) FindAllSubmatch(b []byte, n int) [][][]byte
func (re *Regexp) FindAllSubmatchIndex(b []byte, n int) [][]int
func (re *Regexp) FindIndex(b []byte) (loc []int)
func (re *Regexp) FindReaderIndex(r io.RuneReader) (loc []int)
func (re *Regexp) FindReaderSubmatchIndex(r io.RuneReader) []int
func (re *Regexp) FindString(s string) string
func (re *Regexp) FindStringIndex(s string) (loc []int)
func (re *Regexp) FindStringSubmatch(s string) []string
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)不同还可以继续简化成如下几个,其他的只是输入源不一样,其他功能基本是一样的
func (re *Regexp) Find(b []byte) []byte
func (re *Regexp) FindAll(b []byte, n int) [][]byte
func (re *Regexp) FindAllIndex(b []byte, n int) [][]int
func (re *Regexp) FindAllSubmatch(b []byte, n int) [][][]byte
func (re *Regexp) FindAllSubmatchIndex(b []byte, n int) [][]int
func (re *Regexp) FindIndex(b []byte) (loc []int)
func (re *Regexp) FindSubmatch(b []byte) [][]byte
func (re *Regexp) FindSubmatchIndex(b []byte) []int
上述为数据源为[]byte类型的方法
func RegexpFind() {
//Source String
s := "Hello World Fuck World"
src := []byte(s)
//Regular Expression
reg, err := regexp.Compile(`[A-Za-z]{2,4}`)
myutils.CheckError(err, "Regexp error")
//查找匹配的第一个
first := reg.Find(src)
log.Printf("first : %s \n", first)
//查找匹配的所有结果
//参数小于0返回结果,否则返回长度
all := reg.FindAll(src, -1)
log.Printf("All: %s \n", all)
//返回第一个符合条件的起始位置
fi := reg.FindIndex(src)
log.Printf("First index: %v", fi)
//返回所有符合条件的位置
ai := reg.FindAllIndex(src, -1)
log.Printf("All index: %v", ai)
reg2, err := regexp.Compile(`He(.*)Wo(.*)`)
myutils.CheckError(err, "Regexp error")
//查找Submatch,返回数组
//第一个元素是匹配的全部元素
//第二个元素是第一个()里面的
//第三个是第二个()里面的
submatch := reg2.FindSubmatch(src)
log.Printf("Submatch %v \n", submatch)
for _, v := range submatch {
log.Println("\t", string(v))
}
si := reg2.FindSubmatchIndex(src)
log.Printf("Submatch index %v \n", si)
as := reg2.FindAllSubmatch(src, -1)
log.Printf("All Submatch %s \n", as)
}
类型Regexp也定义了匹配函数,与包中同名的函数功能一样(包中的函数实际调用了Regexp的方法)
func (re *Regexp) Match(b []byte) bool
func (re *Regexp) MatchReader(r io.RuneReader) bool
func (re *Regexp) MatchString(s string) bool
func (re *Regexp) ReplaceAll(src, repl []byte) []byte
func (re *Regexp) ReplaceAllFunc(src []byte, repl func([]byte) []byte) []byte
func (re *Regexp) ReplaceAllLiteral(src, repl []byte) []byte
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