- 前言
- Go 与操作系统
- Go 内部机制
- Go 基本数据类型
- 4 组合类型的使用
- 5 数据结构
- 6 Go package 中不为人知的知识
- 7 反射和接口
- 8 Go UNIX 系统编程
- 08.1 关于 UNIX 进程
- 08.2 flag 包
- 8.2 flag 包
- 08.3 io.Reader 和 io.Writer 接口
- 08.4 bufio 包
- 08.5 读取文本文件
- 08.6 从文件中读取所需的数据量
- 08.7 为什么我们使用二进制格式
- 08.8 读取 CSV 文件
- 08.9 写入文件
- 08.10 从磁盘加载和保存数据
- 08.11 再看strings包
- 08.12 关于bytes包
- 08.13 文件权限
- 08.14 处理 Unix 信号
- 08.15 Unix 管道编程
- 08.16 遍历目录树
- 08.17 使用 ePBF
- 08.18 关于 syscall.PtraceRegs
- 08.19 跟踪系统调用
- 08.20 User ID 和 group ID
- 08.21 其他资源
- 08.22 练习
- 08.23 总结
- 9 并发 Goroutines、Channel 和 Pipeline
- 10 Go 并发-进阶讨论
- 11 代码测试、优化及分析
- 12 Go 网络编程基础
- 13 网络编程 - 构建服务器与客户端
04.4.4 正则匹配IPv4地址
一个IPv4地址被.
号分成了四部分,每一部分都由8位二进制组成,十进制范围是0-255,即二进制的范围是00000000
-11111111
。
IPv6的格式更加复杂,本节的代码不适用于IPv6。
本节的代码findIPv4.go
将分为4个部分,第一部分:
> package main
>
> import (
> "bufio"
> "fmt"
> "io"
> "net"
> "os"
> "path/filepath"
> "regexp"
> )
>
> func findIp(input string) string {
> partIp := "(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])"
> grammer := partIp+"\\."+partIp+"\\."+partIp+"\\."+partIp
> matchMe := regexp.MustCompile(grammer)
> return matchMe.FindString(input)
> }
findIPv4.go
的代码相对之前的复杂一些,所以需要使用的包比较多。
这部分代码定义的正则表达式,能够匹配IPv4地址,是整个程序的核心,如果你定义的正则表达式不正确,将永远找不到你想要的IPv4地址!
代码中的正则表达式稍后我会解释,在此之前必须了解IPv4地址的结构,比如IPv4的点分十进制表示方法以及每一部分都不能超过255,只有这样你能写出恰当的正则表达式。
正则表达式partIp
定义了在一个IPv4地址中,每一部分可能出现的情况,比如可能是250-255的三位数,也可能是200-249,100-199,或者10-99两位数,0-9的个位数,以上的情况必须都考虑在内。
grammer
变量定义了IPv4地址的四个部分,每一部分必须匹配partIp
。
findIPv4.go
可以在任意文本文件中帮助你找到IPv4地址。
如果你有特殊需求,比如要搜索特定的IP地址,直接修改findIPv4.go
的正则表达式即可。
第二部分:
> func main() {
> arguments := os.Args
> if len(arguments) < 2 {
> fmt.Printf("usage: %s logfile\n",filepath.Base(arguments[0]))
> os.Exit(1)
> }
> for _, filename := range arguments[1:] {
> f,err := os.Open(filename)
> if err != nil {
> fmt.Printf("error openning file %s\n",err)
> os.Exit(-1)
> }
> defer f.Close()
首先通过os.Args
获取搜索的文件,然后检查命令行参数的长度是否符合要求。接下来通过一个for`循环迭代处理。
第四部分代码:
> r := bufio.NewReader(f)
> for {
> line,err := r.ReadString('\n')
> if err == io.EOF {
> break
> } else if err != nil {
> fmt.Printf("error openning file %s\n",err)
> break
> }
类似于selectColumn.go
的代码,我们使用bufio.ReadString*()
逐行读取文本。
最后一部分:
> ip := findIp(line)
> trail := net.ParseIP(ip)
> if trail.To4() == nil {
> continue
> } else {
> fmt.Println(ip)
> }
> }
> }
> }
对逐行读取的文本执行findIp()
函数,netParseIP()
会再次确保获取的是有效的IPv4地址。
执行findIPv4.go
得到下面的输出:
$ go run findIPv4.go auth.log
116.112.10.1 151.1.51.5 192.168.1.1
其实findIPv4.go
会打印出很多重复的行(如果文件中有很多重复的IPv4地址)。我们可以配合UNIX命令对输出进一步处理,可以获得更加清晰直观的结果:
go run findIPv4.go auth.log | sort -rn | uniq -c | sort -rn
38 191.168.1.1
22 182.12.5.1
....
9 10.18.2.64
sort -rn
将findIPv4.go
的输出作为输入,排序后倒序输出,uniq -c
计算重复ip的出现次数,最后sort -rn
按照重复ip的出现次数倒叙输出。
再次强调,
findIPv4.go
的核心是正则表达四的实现。如果正则表达式定义错误了,就会匹配不到你想要的数据,或者匹配到错误的数据。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论