学习正则表达式:nginx日志
转眼间进入csdn已经四年了,白嫖了四年的资源,不过依旧是一个小白,哈哈哈.....废话不多说正题开始。
在学习正则表达式之前,咱们先来了解一下,正则表达式是做什么的,度娘问一下。
正则表达式, regex 或者 regexp[1] (有时称为有理表达式)[2][3]是定义搜索模式的字符序列。通常这种模式通过字符串搜索算法用于字符串上的“查找”或“查找并替换”操作,或者用于输入验证。它是在理论计算机科学和形式语言理论中发展起来的一种技术。
总结一下:用来字符串搜索的算法,用于字符串上的“查找”或“查找并替换”操作。
前些天,小编的一个朋友问了一个问题:如何解析nginx日志文件,并存入数据库中,随后我立即查看了一下nginx日志,发现这根本没有啥相通之处,不能用平常的字符串截取的方法进行截取,随后赶紧去找度娘查了一下,然后左看右看,发现正则表达式可以进行一个拆分,但是由于很久没有用正则表达式了,全给搞忘了,大佬们写的表达式拆开还可以认识字符,合起来就是认不得,于是小编就开始研究起来了。在长达好几个小时的研究下,终于简单认识了正则表达式,以下简单介绍一下。本节所有代码全是java代码。
单个字符查找:String regx = "a";
字符串查找:String regx = "akff";
特殊字符查找 | |
换行符 | \n |
换页符 | \f |
回车符 | \r |
空白符 | \s |
制表符 | \t |
具体用法,小编在这就不细细书写了
匹配区间进行模糊查找
写法1 | 写法2 | 含义 |
[0-9] | \d | 匹配0到9的数字 |
\D(大写) | 匹配非0到9的数字 | |
[A-Za-z0-9] | \w | 匹配常用所有的字符 |
\W(大写) | 匹配非常用所有的字符 | |
\s | 匹配空白字符 | |
\S(大写) | 匹配所有非空白字符 |
简单的代码测试,各位同学慢慢看
-
public class RegxTest2 {
-
public static void main(String[] args) {
-
String regx_d = "\\d";
-
String regx_D = "\\D";
-
String regx_w = "\\w";
-
String regx_W = "\\W";
-
String regx_s = "\\s";
-
String regx_S = "\\S";
-
-
String str = "asdfas()((&*9afsd7()*)fas80.. asdf";
-
Pattern pattern = Pattern.compile(regx_d);
-
Matcher matcher = pattern.matcher(str);
-
while (matcher.find()) {
-
System.out.println(matcher.group());
-
}
-
System.out.println("----------这是分割线-----------");
-
pattern = Pattern.compile(regx_D);
-
matcher = pattern.matcher(str);
-
while (matcher.find()) {
-
System.out.println(matcher.group());
-
}
-
System.out.println("----------这是分割线-----------");
-
pattern = Pattern.compile(regx_w);
-
matcher = pattern.matcher(str);
-
while (matcher.find()) {
-
System.out.println(matcher.group());
-
}
-
System.out.println("----------这是分割线-----------");
-
pattern = Pattern.compile(regx_W);
-
matcher = pattern.matcher(str);
-
while (matcher.find()) {
-
System.out.println(matcher.group());
-
}
-
System.out.println("----------这是分割线-----------");
-
pattern = Pattern.compile(regx_s);
-
matcher = pattern.matcher(str);
-
while (matcher.find()) {
-
System.out.println(matcher.group());
-
}
-
System.out.println("----------这是分割线-----------");
-
pattern = Pattern.compile(regx_S);
-
matcher = pattern.matcher(str);
-
while (matcher.find()) {
-
System.out.println(matcher.group());
-
}
-
System.out.println("----------这是分割线-----------");
-
}
-
}
以上都是匹配单个字符的通用匹配符,接下来是多字符匹配区间写法
写法 | 含义 |
? | 匹配 0个或1个 |
* | 匹配大于等于0个字符 |
匹配大于等于1个 |
还有一种特殊的写法,利用大括号{ },完全的写法{min,max}
写法 |
含义 |
{x} |
特定的匹配x次 |
{min,} | 至少min次 |
{min,max} | 介于min到max次之间 |
{0,max} | 至多max次 |
以上的匹配都是书写于需要匹配的字符或字符串后
例如:查找字符串中所有连续的数字
String regx_d = "\\d*"; String str = "asfasdfasd324432asd233"; Pattern pattern = Pattern.compile(regx_d); Matcher matcher = pattern.matcher(str); while (matcher.find()) { if (!"".equals(matcher.group())) { System.out.println(matcher.group()); } }
例如:查找字符串中所有连续的常用字符
String regx_d = "\\w*"; String str = "asfasdfasd32443))2asd23**3"; Pattern pattern = Pattern.compile(regx_d); Matcher matcher = pattern.matcher(str); while (matcher.find()) { if (!"".equals(matcher.group())) { System.out.println(matcher.group()); } }
或者利用{}表达式
String regx_d = "\\w{1,}";
其余部分小编不再演示,最后最重要的分组部分
如果需要匹配多个字符串类型,则需要用()将需要匹配的部分放入到括号里面
例如:
String regx_d = "(\\d*.\\d*)\\s([a-z]*.[a-z]*)";
这个里面分了两组,第一组是查询111.11111这种数字类型的数据,然后第二组是查询sds.sda这种小写字母类型的数据,输出的时候使用以下方式进行输出,如果是group(0)输出查到的完整的第一个数据(122.2312 www.ccc)
System.out.println(matcher.group(1));//输出查找到的第一个匹配模式中第一个括号内的数据
System.out.println(matcher.group(2));//输出查找到的第一个匹配模式中第二个括号内的数据
String regx_d = "(\\d*.\\d*)\\s([a-z]*.[a-z]*)"; String str = "122.2312 www.ccc 11223.12312 fafas.gdsdg"; Pattern pattern = Pattern.compile(regx_d); Matcher matcher = pattern.matcher(str); matcher.find(); System.out.println(matcher.group(0));//输出查到的完整的第一个数据(122.2312 www.ccc) System.out.println(matcher.group(1));//输出查到的完整的第一个数据的第一个匹配括号的内容(122.2312) System.out.println(matcher.group(2));输出查到的完整的第一个数据的第二个匹配括号的内容(www.ccc)
为什么不进行全部查找呢,这个小编就没有细细的去分析了,如果需要输出全部结果,则需循环查找,因为matcher.find()只要找到第一个匹配成功之后就会停止,如需继续匹配则需循环匹配
while (matcher.find())
在学完以上的匹配规则之后,接下来就是我们的重头戏,nginx日志匹配,首先我们来观察一下一般的nginx日志
127.0.0.1 - - [26/Mar/2022:22:32:13 0800] "GET /eduservice/teacher/info?token=undefined HTTP/1.1" 200 101 "http://localhost:9528/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.74 Safari/537.36 Edg/99.0.1150.46"
是不是看完之后,开始吐槽了,小编看完之后也和你是一样的心情
我们开始简单的分析,首先是ip:127.0.0.1 众所周知ip一般都是固定的模式,我们就可以得出匹配规则,这里面的“.”表示匹配一个普通的字符
String nginxRegex1 = "(\\d .\\d .\\d .\\d )"
接下来是访问时间: [26/Mar/2022:22:32:13 0800] ,这里面是不是也是固定的格式,格式化的日期和一个时区,是不是也是固定的搭配,根据这搭配进行编写规则即可,小编使用的更简单的一种匹配规则,利用中括号,管他里面是啥,只要匹配中括号即可,这里面的“.”表示所有的字符都可以匹配
String nginxRegex5 = "(\\[.*\\])";
接下来的是请求方式,资源参数以及请求协议:"GET /test/test/test?token=safas HTTP/1.1",基本上也是一些固定的格式,在这里小编偷偷懒,没有具体的去区别,就把这块的内容用引号区别,但是,后面的请求根路径以及客户端信息浏览器信息也是用双引号引起来的,这个时候,我就直接用的引号来截取数据,然后在进行一个分别赋值,这里的“.”也表示通配符,“?”表示一次匹配一个,也可用大括号
String nginxRegex4 = "(\".*?\")";
接下来是响应状态码以及请求时间(毫秒)200 101,因为状态码市固定的三位数,响应时间不固定,但至少都是大于0的,所以使用“ ”而不用“*”
String nginxRegex3 = "(\\d{3}\\s\\d )";
最后是代码,因为小编为了更好的能够区别每一块的内容,就进行了分别查找,就没有统一查找,因为只是简单的实现,并没有存入数据库,如有存入数据库需要,则用一个list进行保存,然后批量插入数据库
接下来就是全部代码
-
public class RegxTest {
-
public static void main(String[] args) {
-
String nginxLog ;
-
try {
-
File file = new File("日志文件路径");
-
FileInputStream fis = new FileInputStream(file);
-
//Construct BufferedReader from InputStreamReader
-
BufferedReader br = new BufferedReader(new InputStreamReader(fis));
-
String line = null;
-
while ((line = br.readLine()) != null) {
-
nginxLog = line;
-
//匹配查询ip地址
-
String nginxRegex1 = "(\\d .\\d .\\d .\\d )";
-
//匹配查询状态码以及响应时间
-
String nginxRegex3 = "(\\d{3}\\s\\d )";
-
//匹配所有的双引号信息
-
String nginxRegex4 = "(\".*?\")";
-
//匹配以[号开头的]号结尾的信息
-
String nginxRegex5 = "(\\[.*\\])";
-
//为了区别,分开编译
-
Pattern pattern1 = Pattern.compile(nginxRegex1);
-
Pattern pattern3 = Pattern.compile(nginxRegex3);
-
Pattern pattern4 = Pattern.compile(nginxRegex4);
-
Pattern pattern5 = Pattern.compile(nginxRegex5);
-
-
Matcher matcher1 = pattern1.matcher(nginxLog);
-
Matcher matcher3 = pattern3.matcher(nginxLog);
-
Matcher matcher4 = pattern4.matcher(nginxLog);
-
Matcher matcher5 = pattern5.matcher(nginxLog);
-
-
try {
-
matcher1.find();
-
matcher3.find();
-
matcher5.find();
-
NginxAccessLog nginxLog1 = new NginxAccessLog();
-
nginxLog1.setIp(matcher1.group(0));
-
nginxLog1.setTimeZone(matcher5.group(0));
-
nginxLog1.setStateResponseTime(matcher3.group(0));
-
int flag = 0;
-
while (matcher4.find()) {
-
flag ;
-
if (flag == 1) {
-
nginxLog1.setMethodPath(matcher4.group(0));
-
} else if (flag == 2) {
-
nginxLog1.setUrl(matcher4.group(0));
-
} else {
-
nginxLog1.setUserAgent(matcher4.group(0));
-
}
-
}
-
System.out.println(nginxLog1);
-
-
} catch (Exception e) {
-
e.printStackTrace();
-
}
-
}
-
br.close();
-
} catch (IOException e) {
-
e.printStackTrace();
-
}
-
}
-
}
以下是存储日志实体类
-
-
public class NginxAccessLog {
-
// 日志访问ip
-
private String ip;
-
// 访问时间以及时区
-
private String timeZone;
-
// 请求的方式,资源路径及参数
-
private String methodPath;
-
// 状态码,及响应时间
-
private String stateResponseTime;
-
// 请求根url
-
private String url;
-
}
这是小编第一次写文章,如有写的不好的地方请给予指正,私信给小编喔,小编会尽快给予答复,以后小编也会不定期的更新各种小知识,如果你遇到不会的,可以私信小编,一起讨论学习,如有版权等问题请私信小编。
这篇好文章是转载于:学新通技术网
- 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
- 本站站名: 学新通技术网
- 本文地址: /boutique/detail/tanhgbfeeh
-
photoshop保存的图片太大微信发不了怎么办
PHP中文网 06-15 -
Android 11 保存文件到外部存储,并分享文件
Luke 10-12 -
word里面弄一个表格后上面的标题会跑到下面怎么办
PHP中文网 06-20 -
《学习通》视频自动暂停处理方法
HelloWorld317 07-05 -
photoshop扩展功能面板显示灰色怎么办
PHP中文网 06-14 -
微信公众号没有声音提示怎么办
PHP中文网 03-31 -
excel下划线不显示怎么办
PHP中文网 06-23 -
怎样阻止微信小程序自动打开
PHP中文网 06-13 -
excel打印预览压线压字怎么办
PHP中文网 06-22 -
TikTok加速器哪个好免费的TK加速器推荐
TK小达人 10-01