正则表达式
正则表达式到底是什么鬼
表示文本规则的一种类似于集合的东西,即匹配某种字符串的集合。
简单点说,在简单的Windows操作中你肯定使用过*
和?
的通配符,其中*
代表任意的字符串,
元字符
\b
分界处字符代表单词的开头或者结尾不匹配单词分割字符中的任何一个,他自己时匹配一个位置
\s
匹配任意空白字符,包括各,制表符(TAB),换行符(\n)等
\w
匹配字母或数字或下划线或汉字等
\d
匹配一个数字
.
匹配除了换行符以外的任意字符
*
代表的不是字符,也不是位置,而是数量——他指定*
前面的内容可以连续重复出现任意次。*
和.
连接到一起就意味着任意数量的不包括换行的字符
+
类似于*匹配一个或者多个,而 *
可能是0次
^
匹配一个位置——字符串的开始
$
匹配一个位置——字符串的结束
\
字符转义
语法 | 说明 |
---|---|
* | 重复零次或者更多次 |
+ | 重复一次或更多次 |
? | 重复零次或一次 |
{n} | 重复n次 |
{n,} | 重复n次或更多次 |
{n,m} | 重复n到m次 |
字符类
[ ]
表示一个字符范围[0-9]表示\d
[a-z0-9A-Z]表示\w
(只考虑英文字符)
\(?0\d{2}[) -]?\d{8}
分支条件
|
分支条件
0\d{2}-\d{8}|0\d{3}-\d{7}
能匹配两种格式的字符串
\(0\d{2}\)[- ]?\d{8}|0\d{d}[- ]?\d{8}
- 分支条件注意条件的顺序,分支是从左到右的测试每个条件,如果满足了某个分支的话就不会管其他的分支。
分组
重复当个字符前面已经说了(直接在字符后面加上限定符),重复多个字符就需要用小括号来制定子表达式(分组)
- (\d{1,3}\.){3}\d{1,3}
简单的IP地址匹配表达式,但是最后匹配到256.555.888.545这种不可能存在的IP地址,大家不要被《24》第三季的编剧给忽悠了……
- 正确的是((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)\.
反义
一般语言中都有非语句,当然正则表达式中肯定也是存在的
代码 | 说明 |
---|---|
\W | 匹配任意不是字母,数字,下划线,汉字的字符 |
\S | 匹配任意不是空字符的字符 |
\D | 匹配任意非数字的字符 |
\B | 匹配不是以单词开头或结束的 |
[^x] | 匹配除了x以外得任意字符 |
[^aeiou] | 匹配除了元音字符以外的任意字符 |
\S+
匹配不包含空白符的字符串
<a[^>]+>
匹配用尖括号括起来的以a开头的字符串
- 正则表达式中的单词和老外的单词不一样,这里表示的是多于一个连续的\w
后向引用
使用小括号之后指定一个子表达式后,重新引用匹配这个子表达式就是后项引用的过程,其中每个分组自动分配个组号,规则:从左往右,第一个为1以此类推。
\b(\w+)\b\s+\1\b
可以用来匹配重复的单词,例如“go go”等,其中\1就代表前面的分组(\w+)
- 同时也可以自己指定分组:(?<word>\w+)
(或者把尖括号换成’也行:(?'Word'\w+)
),这样就把\w+的组名指定为word了,可以使用\k<word>
引用分组word。
所以上面的例子就可以写成\b(?<word>\w+)\b\s+\k<word>\b
分类 | 语法 | 说明 |
---|---|---|
捕获 | (exp) | 匹配exp,并捕获文本到自动命名的组里 |
(?<name>exp) | 匹配exp,捕获内容并命名为name的组 | |
(?:exp) | 匹配exp,不捕获匹配的的文本,也不给文本分配组号 | |
零宽断言 | (?=exp) | 匹配exp前面的位置 |
(?<exp) | 匹配exp后面的位置 | |
(?!exp) | 匹配后面跟的不是exp的位置 | |
(?<!exp) | 匹配前面不是exp的位置 | |
注释 | (?#commment) | 添加注释 |
- (?=exp)仅仅是匹配其中的内容,不会有过多的操作
正零宽断言
什么是零宽断言,只有小学功底的同学,一定很难理解,不管他叫啥名字了,说白了这个东西就是匹配一个符合某个表达式前面的表达式。
(?=exp)也叫零宽度正预测先行断言,它断言自身出现位置后面能匹配表达式exp。比如\b\w+(?=ing\b),匹配以ing结尾的单词前面的部分(除ing以外的部分),如“I’m going to study Python”这样将会匹配’go’
同理(?<=exp)为零宽度正回顾后发断言,(?<=\bro)\w+\b,尝试下总比看着好
(?<=\s+)\d+(?=\s+)
负零宽断言
是前面提及关于正零宽断言的反义
\b\w*q[^u]\w*\b匹配包含后面不是字母u的单词q的单词,但是如果你思维足够敏捷(我是不行了)你会发现,如果q在单词的末尾,例如Iraq,Benq,这个表达式就会出错。这是因为[^u]总是要匹配一个字符,所以q在末尾的话他就会匹配单词的分割符‘,’,后面的\w*\b将会匹配下一个单词。这个时候我们的主角就出来了,我们的主角只是匹配一个位置不会消耗 任何字符。上面的例子我们可以这样解决问题:‘\b\w*q(?!u)\w*\b’
零宽度负预测先行断言(?!exp),断言此位置的后面不能匹配表达式exp,例如\d{3}(?!\d)匹配三个数字且后面不能是数字。
同理我们就知道(?
贪婪与懒惰
当正则表达式中包含能接受重复的限定符时,通常的行为是(在使整个表达式能得到匹配的前提下)匹配尽可能多的字符(贪婪模式)考虑这个表达式:a.*b,它将会匹配最长的以a开始,以b结束的字符串。如果用它来搜索aabab的话,它会匹配整个字符串aabab 。这被称为贪婪匹配。
有时,我们更需要懒惰匹配,也就是匹配 尽可能少的字符。前面给出的限定符都可以被转化为懒惰匹配模式,只要在它后面加上一个问号?。这样.*?就意味着匹配任意数量的重复,但是在能使整个匹配成功的前提下使用最少的重复。现在看看懒惰版的例子吧:
a.*?b 匹配最短的,以a开始,以b结束的字符串。如果把它应用于aabab的话,它会匹配aab(第一到第三个字符) 和ab(第四到第五个字符)
薛定谔的猫和谁的狗