regex match
正则表达升主要内容大致可以分为两块
- 最基础的部分(字符组,快捷方式,匹配多个数据)
- 进阶的应用(分组与回溯引用,替换和标记,先行断言,后行断言)
1 基础
1.1 match
最基础的match,直接输入字符就可以匹配到string中的所有包含字符的内容
1.2 字符组
1
2
3
[]//允许可能出现的一组字符
比如
[Cc]++ is a good language//字符组内的的大小写c都可以匹配到
当你要匹配多个字符的时候
1
2
//比如要匹配Rust,rust,ruby,rube
[rR]u[sb][tye]
当你要匹配一个区间的时候
1
2
3
4
[0-9]//匹配所有的数字
[a-z]//匹配所有的小写字母
[A-Z]//匹配所有的大写字母
[a-zA-Z0-9]//是可以连接多个条件的
当你要匹配一个特殊字符的时候,需要考虑转义
1
[\[]//可以匹配\
当你不想匹配数字的时候,可以用到取反操作符
1
2
[^0-9]//代表匹配除了数字之外的字符
[^你]//不能匹配你
1.3 快捷方式
字符和数字匹配,该快捷方式也可以用在字符组中
\w 匹配任何单词字符等价于[a-z0-9A-Z]
\b 匹配任何数字等价于[0-9]
\s 匹配空白
快捷方式的取反就直接将小写改成大写即可
单词的边界匹配
1
\b 匹配单词的边界,\bcode\b就只能匹配的code一词
开头和结束
1
2
^ 指定的是一个字符串的开始
& 指定的是一个字符串的结束
匹配小数
1
^\d+?\.(\d+)$
1.4 任意字符
匹配单个的任意字符号
1
. 匹配任意的单个字符,只能出现在字符组外,且无法匹配换行符
1.5 可选字符
?
符号指定一个字符、字符组或其他基本单元可选,这意味着正则表达式引擎将会期望该字符出现零次或一次。
1
.? 匹配任意一个字符出现或者不出现
1.6 重复
在一个字符组后加上{N}
就可以表示在它之前的字符组出现N
次
1
2
3
4
\d{4} 数字,出现了4次
\d{4,8} 此处代表重复的区间,既可以出现4是下界,8是上界。不过有8个数字的时候是优先匹配上界的,这是正则默认二点贪婪模式
\d{4,8}?解除贪婪模式
\d{1,} 匹配一个或者无数个数字
另外这里也有两个速写符号
1
2
+ 等价于{1,}
* 等价于{0,}
1.7 总结
[Pp]ython | 匹配 “Python” 或 “python”。 |
---|---|
rub[ye] | 匹配 “ruby” 或 “rube”。 |
[abcdef] | 匹配中括号内的任意一个字母。 |
[0-9] | 匹配任何数字。类似于 [0123456789]。 |
[a-z] | 匹配任何小写字母。 |
[A-Z] | 匹配任何大写字母。 |
[a-zA-Z0-9] | 匹配任何字母及数字。 |
[^au] | 除了au字母以外的所有字符。 |
[^0-9] | 匹配除了数字外的字符。 |
实例 | 描述 |
---|---|
. | 匹配除 “\n” 之外的任何单个字符。要匹配包括 ‘\n’ 在内的任何字符,请使用象 ‘[.\n]’ 的模式。 |
? | 匹配一个字符零次或一次,另一个作用是非贪婪模式 |
+ | 匹配1次或多次 |
* | 匹配0次或多次 |
\b | 匹配一个长度为0 的子串 |
\d | 匹配一个数字字符。等价于 [0-9]。 |
\D | 匹配一个非数字字符。等价于 [^0-9]。 |
\s | 匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。 |
\S | 匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。 |
\w | 匹配包括下划线的任何单词字符。等价于’[A-Za-z0-9_]’。 |
\W | 匹配任何非单词字符。等价于 ‘[^A-Za-z0-9_]‘。 |
\b | 匹配一个长度为0 的子串 |
贪婪模式
在默认情况下,正则表达式是“贪婪”的,即尽可能匹配更多的文本。而使用解除贪婪模式修饰符,可以使正则表达式变得“非贪婪”,即尽可能匹配更少的文本
在正则表达式中,解除贪婪模式通常使用问号(?)来表示。下面是一些常用的量词及其对应的解除贪婪模式:
*?
:匹配零次或多次,并且尽可能少地匹配。 +?
:匹配一次或多次,并且尽可能少地匹配。 ??
:匹配零次或一次,并且尽可能少地匹配。 {n,m}?
:匹配至少n次、至多m次,并且尽可能少地匹配。
2 高级应用
2.1 分组
分组极其的简单()内的就是一个group,比如要提取号码的两部分
1
2
(\d{4})-(\d{7})
号码:0731-1234567
2.2 条件或
采用分组的同时还可以加上条件或,例如我们想匹配所有的文件后缀名
1
2
(.jpg|.mov|.png)
(\..+)
2.3 非捕获分组
有时候,我们并不需要捕获某个分组的内容,但是又想使用分组的特性。(主要是为了或)
这个时候就可以使用非捕获组,从而不捕获数据,还能使用分组的功能。
例如想要匹配两个字母组成的单词或者四个字母组成的单词就可以使用非捕获分组:
1
\b(?:\w{2}|\w{4})\b
2.4 技巧
捕获年月日:
1
2
3
4
5
6
7
20200102
2020-01-02
2020-1-2
2020.01.02
2020 01 02
2020 1 2
2020/01/02
利用分组捕获
1
(\d{4})[\-\.\s/]?(\d{2}|\d{1})[\-\.\s/]?(\d{2}|\d{1})
2.5 分组的回溯引用
简言之,我们希望之前匹配过的一个表达式再次出现
正则表达式还提供了一种引用之前匹配分组的机制,有些时候,我们或许会寻找到一个子匹配,该匹配接下来会再次出现。
例如,要匹配一段 HTML 代码,比如:0123<font>提示</font>abcd
,可能会编写出这样一段正则表达式:
1
<\w+>.*?</\w+>
但是我们希望的是font匹配/font,而不是/div之类的
这个时候,可以利用分组的回溯引用
1
<(\w+)>.*?</\1>
使用\N
可以引用编号为N
的分组.
例如匹配abXXXXba这种单词
1
(\w)(\w).*(\2)(\1)
或者匹配aabbbbaa这种
1
(\w{2,4})(\1)
2.6 正向先行断言
正向先行断言:(?=表达式)
,指在某个位置向右看,表示所在位置右侧必须能匹配表达式
1
我喜欢你 我喜欢 我喜欢我 喜欢 喜欢你
如果要取出喜欢两个字,要求这个喜欢后面有你,这个时候就要用如下的写法
1
喜欢(?=你)
- 先行断言可以用来判断字符串是否符合特定的规则,例如提取包含至少一个大小写字母的字符串:
1
(?=.*?[a-z])(?=.*?[A-Z]).+
- 之后编写一个验证密码强度的正则
1
2
3
4
至少一个大写字母
至少一个小写字母
至少一个数字
至少8个字符
1
(?=.*[a-z]{1})(?=.*[A-Z]{1})(?=.*\d{1})(?=\w{8,})
2.7 反向先行断言
反向先行断言(?!表达式)
的作用是保证右边不能出现某字符。
如果要取出喜欢两个字,要求这个喜欢后面没有你,这个时候就要这么写:
1
喜欢(?!你)
例如排除邮箱中是qq邮箱的数据:
1
.+@(?!qq).+\.com
2.8 正向后行断言
先行断言和后行断言只有一个区别,即先行断言从左往右看,后行断言从右往左看。
正向后行断言:(?<=表达式)
,指在某个位置向左看,表示所在位置左侧必须能匹配表达式
例如匹配王姓同学
1
(?<=王).+
2.9 反向后行断言
(?<!表达式)
如果要取出喜欢两个字,要求喜欢的前面没有我,后面没有你,这个时候就要这么写:(?<!我)喜欢(?!你)
。
1
2
匹配$xxxxx$
(?<!\$)\$[^\$]+\$(?!\$)
2.10 边界类断言
^
匹配输入的开头。如果多行模式设为 true,^
在换行符后也能立即匹配,比如/^A/
匹配不了”an A”里面的 “A”,但是可以匹配”An A”里面第一个”A”。
$
匹配输入的结束。如果多行模式设为 true,$
在换行符前也能立即匹配,比如 /t$/
不能匹配 “eater” 中的 “t”,但是可以匹配 “eat” 中的 “t”.
\b
匹配一个单词的边界,这是一个字的字符前后没有另一个字的字符位置,例如在字母和空格之间。需要注意的是匹配的单词边界不包括在匹配中。换句话说,匹配字边界的长度为零。
一些例子:
/\bm/
在 “moon” 中匹配到 “m”/oo\b/
在 “moon” 中不会匹配到 “oo”, 因为 “oo” 后面跟着 “n” 这个单词字符。/oon\b/
在 “moon” 中匹配 “oon”,因为 “oon” 是这个字符串的结尾,因此后面没有单词字符/\w\b\w/
将永远不会匹配任何东西,因为一个单词字符后面永远不会同时有一个非单词字符和一个单词字符。
\B
匹配非单词边界。这是上一个字符和下一个字符属于同一类型的位置:要么两者都必须是单词,要么两者都必须是非单词,例如在两个字母之间或两个空格之间。字符串的开头和结尾被视为非单词。与匹配的词边界相同,匹配的非词边界也不包含在匹配中。例如,/\Bon/
在“at noon”中匹配“on” ,/ye\B/
在 “possibly yesterday”中匹配”ye” 。