高级的正则表达式示例

本节你将学习到如何在Apache web服务器的日志文件中匹配特定格式的时间与日期字符串。同时,你也会了解到将不同格式的时间与日期写入日志文件中。与上一节一样,我们需要逐行读取Apache日志文件。

本节的代码changeDT.go将分为4部分展示,可以发现changeDT.go是第三章中timeDate.go的升级版本,只不过是使用两个正则表达式匹配不同的时间与日期。

要注意的是不要试图在程序的第一个版本就达到尽善尽美,最好的方法就是小版本快速迭代。

第一部分代码:

  1. package main
  2. import (
  3. "bufio"
  4. "fmt"
  5. "io"
  6. "os"
  7. "regexp"
  8. "strings"
  9. "time"
  10. )
  11. func main() {
  12. arguments := os.Args
  13. if len(arguments) ==1 {
  14. fmt.Println("Please provide one text file to process")
  15. os.Exit(1)
  16. }
  17. fileName := arguments[1]
  18. f, err := os.Open(fileName)
  19. if err != nil {
  20. fmt.Printf("error opening file %s ",err)
  21. os.Exit(1)
  22. }
  23. defer f.Close()
  24. notAmatch := 0
  25. r := bufio.NewReader(f)
  26. for{
  27. line, err := r.ReadString('\n')
  28. if err == io.EOF {
  29. break
  30. } else if err != nil{
  31. fmt.Printf("error reading file %s,",err)
  32. }

首先我们要打开要读取的文件,并逐行读取其内容。变量notAmatch存储输入文件中不匹配两个正则表达式的条目。

第三部分代码:

  1. r1 := regexp.MustCompile(`.*\[(\d\d\/\w+/\d\d\d\d:\d\d:\d\d:\d\d.*)\] .*`)
  2. if r1.MatchString(line) {
  3. match := r1.FindStringSubmatch(line)
  4. d1, err := time.Parse("02/Jan/2006:15:04:05 -0700", match[1])
  5. if err == nil {
  6. newFormat := d1.Format(time.Stamp)
  7. fmt.Printf(strings.Replace(line,match[1],newFormat,1))
  8. } else {
  9. notAmatch++
  10. continue
  11. }
  12. }

可以看出只要代码执行到if中,就会执行continue,这意味着程序会继续执行本代码块中的逻辑。第一个正则表达式会匹配格式为21/Nov/2017:19:28:09 +0200的时间与日期字符串。

函数regexp.MustCompile()regex.Compile()作用相同,只不过在解析失败时会触发panic。这种情况下你只能实现一种匹配,所以就要使用regexp.FindStringSubmatch()

第三部分代码:

  1. r2 := regexp.MustCompile(`.*\[(\w+\-\d\d-\d\d:\d\d:\d\d:\d\d.*)\] .*`)
  2. if r2.MatchString(line) {
  3. match := r2.FindStringSubmatch(line)
  4. d1, err := time.Parse("Jan-02-06:15:04:05 -0700", match[1])
  5. if err == nil {
  6. newFormat := d1.Format(time.Stamp)
  7. fmt.Print(strings.Replace(line, match[1], newFormat, 1))
  8. } else {
  9. notAmatch++
  10. }
  11. continue
  12. }
  13. }

匹配的第二种时间格式是Jun-21-17:19:28:09 +0200,尽管本程序实现了两种格式的匹配,但当你掌握正则表达式之后,你可以实现任意形式的匹配。

最后一部分代码将会打印出日志中没有匹配的条目数量:

  1. fmt.Println(notAmatch, "lines did not match!")
  2. }

执行ChangDT.go后得到下面的输出:

$ go run changDT.go

04.4.3 高级的正则表达式示例 - 图1