本节你将学习到如何在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