高级的正则表达式示例
本节你将学习到如何在Apache web服务器的日志文件中匹配特定格式的时间与日期字符串。同时,你也会了解到将不同格式的时间与日期写入日志文件中。与上一节一样,我们需要逐行读取Apache日志文件。
本节的代码changeDT.go
将分为4部分展示,可以发现changeDT.go
是第三章中timeDate.go
的升级版本,只不过是使用两个正则表达式匹配不同的时间与日期。
要注意的是不要试图在程序的第一个版本就达到尽善尽美,最好的方法就是小版本快速迭代。
第一部分代码:
package main
import (
"bufio"
"fmt"
"io"
"os"
"regexp"
"strings"
"time"
)
func main() {
arguments := os.Args
if len(arguments) ==1 {
fmt.Println("Please provide one text file to process")
os.Exit(1)
}
fileName := arguments[1]
f, err := os.Open(fileName)
if err != nil {
fmt.Printf("error opening file %s ",err)
os.Exit(1)
}
defer f.Close()
notAmatch := 0
r := bufio.NewReader(f)
for{
line, err := r.ReadString('\n')
if err == io.EOF {
break
} else if err != nil{
fmt.Printf("error reading file %s,",err)
}
首先我们要打开要读取的文件,并逐行读取其内容。变量notAmatch
存储输入文件中不匹配两个正则表达式的条目。
第三部分代码:
r1 := regexp.MustCompile(`.*\[(\d\d\/\w+/\d\d\d\d:\d\d:\d\d:\d\d.*)\] .*`)
if r1.MatchString(line) {
match := r1.FindStringSubmatch(line)
d1, err := time.Parse("02/Jan/2006:15:04:05 -0700", match[1])
if err == nil {
newFormat := d1.Format(time.Stamp)
fmt.Printf(strings.Replace(line,match[1],newFormat,1))
} else {
notAmatch++
continue
}
}
可以看出只要代码执行到if
中,就会执行continue
,这意味着程序会继续执行本代码块中的逻辑。第一个正则表达式会匹配格式为21/Nov/2017:19:28:09 +0200
的时间与日期字符串。
函数regexp.MustCompile()
与regex.Compile()
作用相同,只不过在解析失败时会触发panic。这种情况下你只能实现一种匹配,所以就要使用regexp.FindStringSubmatch()
。
第三部分代码:
r2 := regexp.MustCompile(`.*\[(\w+\-\d\d-\d\d:\d\d:\d\d:\d\d.*)\] .*`)
if r2.MatchString(line) {
match := r2.FindStringSubmatch(line)
d1, err := time.Parse("Jan-02-06:15:04:05 -0700", match[1])
if err == nil {
newFormat := d1.Format(time.Stamp)
fmt.Print(strings.Replace(line, match[1], newFormat, 1))
} else {
notAmatch++
}
continue
}
}
匹配的第二种时间格式是Jun-21-17:19:28:09 +0200
,尽管本程序实现了两种格式的匹配,但当你掌握正则表达式之后,你可以实现任意形式的匹配。
最后一部分代码将会打印出日志中没有匹配的条目数量:
fmt.Println(notAmatch, "lines did not match!")
}
执行ChangDT.go
后得到下面的输出:
$ go run changDT.go