sharplook做为专业的日志采集分析系统,涉及的技术点,从后到前着实很多,内容也较为复杂。正则做为日志解析的手段,起着举足轻重的做用,在此小生将晦涩难懂的内容,拆解出来以便学习之用。git
维基百科对其的定义是:“正则表达式,又称正规表示式、正规表示法、正规表达式、规则表达式、常规表示法(英语:Regular Expression,在代码中常简写为regex、regexp或RE),是计算机科学的一个概念。正则表达式使用单个字符串来描述、匹配一系列匹配某个句法规则的字符串。在不少文本编辑器里,正则表达式一般被用来检索、替换那些匹配某个模式的文本。” 目前许多程序设计语言都支持利用正则表达式进行字符串操做。简单地理解就是,正则表达式是用于匹配字符串中字符组合的模式,要么匹配字符,要么匹配位置。程序员
目前暂定如下内容将在后期分享于诸君,本篇先介绍正则表达式里面的字符匹配,实例都将以JavaScript代码演示,其实正则没有语言界限,小生也不是强权主义,只是写来方便罢了。正则表达式
正则表达式不只能够精确匹配还能够模糊匹配,假若只有精确匹配,那正则就太弱了,也不值得在此继续聊下去。编辑器
const reg = /hello, world/; console.log(reg.test('hello ,world')); // => true
而强大的模糊匹配,有两个方向上的“模糊”: 横向模糊和纵向模糊。工具
横向模糊指的是,一个正则可匹配的字符串的长度是不肯定的,能够是多种状况。学习
其实现的方式是量词。例如{m,n},表示最少出现m次,最多出现n次。例如正则/ab{2,4}c/
表示匹配一个“a”,紧接着匹配2个或者3个或者4个连续的字母“b”,最后匹配字母“c”。测试
可视化图以下:spa
测试以下:设计
const reg = /ab{2,4}c/g; const string = 'abc abbc abbbc abbbbc abbbbbc'; console.log(string.match(reg)); // => ['abc', 'abbc', 'abbbc', 'abbbbc']
正则
/ab{2,4}c/g
中的‘g’是正则的修饰符,表示此正则采用全局匹配,按照顺序匹配出全部符合正则的字符串,g表示global。日志
纵向模糊指的是,一个正则匹配的字符串,当匹配到某一位的字符时,并非一个特定的字符,其有多种可能性。
其实现的方式是字符组。例如[abc]
,表示匹配的字符多是“a”,“b”,“c”中的一个。 例如/a[123]b/
表示匹配的是“a1b”,“a2b”,“a3b”其中一个。
可视化图以下:
测试以下:
const reg = /a[123]c/g; const string = 'a1c a2c a3c a4c'; console.log(string.match(reg)); // => ['a1c', 'a2c', 'a3c'];
字符组虽然是组的概念,可是只是表示其中一个字符。
例如[abc]
,表示匹配其中一个字符,它能够是“a”,“b”,“c”之一。
若是字符组中的字符很是多的话,怎么办呢?可使用范围表示法。
例如“1234567abcdefgHIJKLMN”但是表示为[1-7a-gH-N]
。用连字符“-”表示简写中间的项。
在这里“-”表示特殊含义,若是正则匹配须要匹配这个字符,好比匹配“a”,“h”,“-”怎么办呢? 能够写成[-ah]
,[ah-]
,[a\-h]
中的一种,这样就能够避免被做为连字符来处理了。
在纵向匹配中,咱们还会遇到一种状况,那就是咱们不但愿匹配到字符组的任何一个字符。例如不能匹配“a”,“b”,“c”。
此时就出现了排除字符组的概念。例如[^abc]
,表示匹配除了“a”,“b”,“c”字符以外的任意一个字符。字符组中第一位放^
脱字符,表示求反的概念。
固然,也有相应的范围表示法,例如:[^a-h]
。
有了字符组的概念以后,咱们就很容易理解系统自带的简写方式了。
\d
: 表示 [0-9]
。表示是一位数字。 记忆方式: 其英文是 digit(数字)。\D
: 表示 [^0-9]
。表示除数字外的任意一个字符。\w
: 表示 [0-9a-zA-Z_]
。表示数字、大小写字母和下划线。记忆方式:w是 word的简写,也表示单词字符。\W
: 表示 [^0-9a-zA-Z_]
。表示除了数字、大小写字母和下划线以外的任意一个字符。非单词字符。\s
: 表示 [\r\v\n\r\f]
。表示空白符,包括空格、水平制表符、垂直制表符、换行符、回车符、换页符。记忆方式: s是 space的首字母,空白字符的单词是 white space。\S
: 表示 [^\r\v\n\r\f]
,表示非空白符。.
: 表示 [^\n\r\u2028\u2029]
。通配符,表示几乎任意字符,除了换行符、回车符、行分隔符和段分隔符除外。记忆方式:想一想省略号 ... 中的每一个点,此处省略了无数个字(什么状况均可能发生)。若是表示任意字符,怎么办? 可使用[\d\D]
,[\w\W]
,[\s\S]
和[^]
中任何一个。
/\d\D\w\W\s\S.[^]/
的可视化表示以下:
量词也称为重复词。理解了{m,n}
后,咱们再来记住一些简写方式。
{m,}
:表示至少出现m次。{m}
:表示出现m次,等价于{m,m}
。?
:表示出现一次或者不出现,等价于{0,1}
。记忆方式: 问号的表示意思,有吗?+
:表示出现一个或者屡次,等价于{1,}
。记忆方式: 加好是追加的意思,先获得一个,之后的再追加。*
:表示出现任意次数,可能不出现。记忆方式: 比如天上的星星,可能一个没有,可能只有零星几个,也可能有无数多。先看一个简单的例子:
const reg = /\d{2,5}/g; const string = '123 1234 12345 123456'; console.log(string.match(reg)); // => ['123', '1234', '12345', '12345']
其中正则/\d{2,5}/
表示匹配连续的数字2次到5次。会匹配2位、3位、4位、5位连续数字。
可是其是贪婪的,它会尽量多的匹配。你能给我 5 个,我就要 5 个。你能给我 3 个,我就要 3 个。
反正只要在能力范围内,越多越好。
可是有时候贪婪并非一件好事(人心不足,蛇吞象)。而惰性匹配,就是尽量少的匹配,例以下:
const reg = /\d{2,5}?/g; const string = '123 1234 12345 123456'; console.log(string.match(reg)); // => ['12', '12', '34', '12', '34', '12', '34', '56']
其中 /d{2,5}?/ 表示,虽然 2 到 5 次都行,当 2 个就够的时候,就再也不往下尝试了。
对惰性匹配的记忆方式是: 量词后面加个问号,问一问你满足了吗,你很贪婪吗?
一个模式能够实现横向匹配和纵向匹配,而多分支能够支持多个子模式任选其一。
具体形式以下(p1|p2|p3)
,其中p一、p2和p3是子模式,用|
(管道符)分隔,表示任选其一。
例如匹配hello
或者world
,正则式为/hello|world/
。
可视化形式以下:
测试以下:
const reg = /hello|world/g; const string = "hello lemon, world is yours!"; console.log(string.match(reg)); // => ['hello', 'world']
须要注意的地方是,he|hello
,你想匹配“hello”这个单词,结果是“he”。
以下实例:
const reg = /he|hello/g; const string = 'hello'; console.log(string.match(reg)); // => ['he']
若是你的正则改成hello|he
。匹配的结果就是“hello”
以下实例:
const reg = /hello|he/g; const string = 'hello'; console.log(string.match(reg)); // => ['hello']
由此可知,多分支结构匹配也是惰性的,当前面匹配上以后,后面就不在匹配了。
正则表达式是一个优秀程序员的基本技能,自己虽然不是很复杂,但内容却比较杂乱,能一步一步理清思路是很重要的,本章主要先介绍了字符的匹配,下一章将介绍位置的匹配。
本文中的正则表达式转化为关系图来展现的工具是Regexper
此文主要参考和学习了老姚的《JavaScript 正则表达式迷你书》,内容清晰明了,在此很是感谢老姚的 free精神,致敬。
[1] 老姚 著《JavaScript 正则表达式迷你书》