正则表达式学习
正则简介
正则表达式(简称 regex或者regexp)允许开发人员根据模式匹配字符串、提取子匹配信息,或简单地测试字符串是否符合该模式。
可以用来:
(1)检查一个串中是否含有符合某个规则的子串,并且可以得到这个子串;
(2)根据匹配规则对字符串进行灵活的替换操作
一、正则基础
-
单词全写:匹配单词
of 匹配含有of单词的内容
-
.符号 : 匹配任意字符,除了换行符
-
^ 符号:字符串开始的地方匹配,不匹配任何字符
-
$ 符号:字符串结束的地方匹配,不匹配任何字符
-
\b :匹配一个单词边界,也就是单词和空格之间的位置,不匹配任何字符
-
[字符列表]:匹配字符集
[bdf]eer 匹配beer deer feer [ab5@] 匹配 "a" 或 "b" 或 "5" 或 "@"
-
[^字符列表] : 除字符集
be[^ou]r 匹配be...r形式的内容中间不包含o,u的内容 [^abc] 匹配 "a","b","c" 之外的任意一个字符 [^A-F0-3] 匹配 "A"~"F","0"~"3" 之外的任意一个字符
-
[起点字符-终点字符] :字母范围
[g-k] 匹配g-k任意字符 [0-9] 匹配0-9任意数字,等价于 /\d/ [f-k] 匹配 "f"~"k" 之间的任意一个字母
-
重复: + * ?{m,n}]
+号 :表示至少重复/出现一次,用于要标识的字符后面,相当于 {1,},比如:"a+b"可以匹配 "ab","aab","aaab". \*号 :表示不出现或者出现一次或者并排出现多次,相当于 {0,},比如:"\^*b"可以匹配 "b","^^^b" ?号 :表示可选,即可有可无,出现0次或者1次,相当于 {0,1},比如:"a[cd]?"可以匹配 "a","ac","ad" {n} :表示确切出现的次数,即准确次数匹配,比如:"\w{2}" 相当于 "\w\w";"a{5}" 相当于 "aaaaa" {m,} :表示至少出现m次,比如:"\w\d{2,}"可以匹配 "a12","_456","M12344" {m,n}:表示出现次数在m和n之间【闭区间】,比如:"ba{1,3}"可以匹配 "ba"或"baa"或"baaa
-
()号:分组,或者捕获分组
(haa) 表示对文本中的 haa 构造分组,为了给表达式分组,我们需要将文本包裹在 () 中 (d)(\w+) "\w+" 将匹配第一个 "d" 之后的所有字符 "xxxdxxxd" (d)(\w+)(d) "\w+" 将匹配第一个 "d" 和最后一个 "d" 之间的所有字符 "xxxdxxx"。虽然 "\w+" 也能够匹配上最后一个 "d",但是为了使整个表达式匹配成功,"\w+" 可以 "让出" 它本来能够匹配的最后一个 "d" (d)(\w+?) "\w+?" 将尽可能少的匹配第一个 "d" 之后的字符,结果是:"\w+?" 只匹配了一个 "x" (d)(\w+?)(d) 为了让整个表达式匹配成功,"\w+?" 不得不匹配 "xxx" 才可以让后边的 "d" 匹配,从而使整个表达式匹配成功。因此,结果是:"\w+?" 匹配 "xxx"
-
(?: ):非捕获分组,可以对表达式进行分组,并确保它不被引用捕获,不会存储,优化性能
例如,如果我们想匹配一个日期格式 2019-11-10 并分别获取年、月、日,我们可以使用捕获分组来实现 (\d{4})-(\d{2})-(\d{2}) 这将创建三个捕获分组,分别保存年、月、日的匹配结果。 但如果我们不需要单独引用这些分组中的数据,我们可以使用非捕获分组来改写表达式: (?:\d{4})-(?:\d{2})-(?:\d{2}) 这样,正则表达式仍然可以匹配相同的日期格式,但不会保存匹配的年、月、日到内存中。
-
()-\n:引用组
反向引用 \1, \2... 举例 1:表达式 "('|")(.*?)(\1)" 在匹配 " 'Hello', "World" " 时,匹配结果是:成功; 匹配到的内容是:" 'Hello' "。再次匹配下一个时,可以匹配到 " "World" "。 举例 2:表达式 "(\w)\1{4,}" 在匹配 "aa bbbb abcdefg ccccc 111121111 999999999" 时,匹配结果是:成功;匹配到的内容是 "ccccc"。再次匹配下一个时,将得到 999999999。这个表达式要求 "\w" 范围的字符至少重复 5 次,注意与 "\w{5,}" 之间的区别 举例3: 单词 ha 和 haa 分组如下: ha-ha,haa-haa 第一组用 \1 来避免重复书写。这里的 1 表示分组的顺序。请在表达式的末尾键入 \2 以引用第二组: (ha)-\1,(haa)-\2
-
|竖线:竖线允许一个表达式包含多个不同的分支。所有分支用 | 分隔,左右两边表达式之间 “或” 关系,匹配左边或者右边。
下面的表达式同时匹配 cat 和 rat。请在末尾添加另一个 |,并输入 dog 以匹配所有单词。 cat rat dog 正则: (c|r)at|dog
-
\转义符:当正则使用 { } [ ] / \ + * . $^ | ? 这些特殊字符 ,为了匹配这些特殊字符本身,我们需要通过 \ 将它们转义。
\r 代表回车 \n 代表换行符 \t 代表制表符 \\ 代表 "\" 本身 \^ 匹配 ^ 符号本身 \$ 匹配 $ 符号本身 \* 匹配 * 符号本身 \. 匹配 .$ 符号本身 \[\] 匹配 [] 符号本身 ... 例如,要匹配文本中的 . 和 *,我们需要在它们前面添加一个 \。 正则: (\*|\.)
-
^插入符: 匹配字符串的开始
我们用 [0-9] 查找数字,若仅查找行首的数字,请在表达式前面加上 ^ Basic Omellette Recipe 1. 3 eggs, beaten 2. 1 tsp sunflower oil 3. 1 tsp butter 正则: ^[0-9]
-
$美元符号: 匹配字符串的结束
例如在 html 的后面添加 $,来查找仅在行末出现的 html https://domain.com/what-is-html.html https://otherdomain.com/html-elements https://website.com/html5-features.html 正则: html$
-
单词字符 \w: 字母、数字和下划线
-
非单词字符 \W
-
数字字符 \d
-
非数字字符 \D
-
空白符 \s
-
非空白符 \S
-
\B 匹配非单词边界,即左右两边都是 “\w” 范围或者左右两边都不是 “\w” 范围时的字符缝隙
二、正则提升
-
零宽断言
-
正向先行断言/正向预搜索: (?=)
例如,我们要匹配文本中的小时值。为了只匹配后面有 PM 的数值,我们需要在表达式后面使用正向先行断言 (?=),并在括号内的 = 后面添加 PM。 文本:Date: 4 Aug 3PM 正则:\d+(?=PM) 结果:3
-
负向先行断言/正向预搜索: (?!)
例如,我们要在文本中匹配除小时值以外的数字。我们需要在表达式后面使用负向先行断言 (?!),并在括号内的 ! 后面添加 PM,从而只匹配没有 PM 的数值。 文本:Date: 4 Aug 3PM 正则:\d+(?!PM) 结果:4
-
正向后行断言/反向预搜索: (?<=)
例如,我们要匹配文本中的金额数。为了只匹配前面带有 $ 的数字。我们要在表达式前面使用正向后行断言 (?<=),并在括号内的 = 后面添加 \$。 文本:Product Code: 1064 Price: $5 正则:(?<=\$)\d+ 结果:5
-
负向后行断言/反向预搜索: (?<!)
例如,我们要在文本中匹配除价格外的数字。为了只匹配前面没有 $ 的数字,我们要在表达式前用负向后行断言 (?<!),并在括号内的 ! 后面添加 \$。 文本:Product Code: 1064 Price: $5 正则:/(?<!\$)\d+/g 结果:1064
-
-
标志/表达式属性:标志改变表达式的输出。这就是标志也称为 修饰符 的原因。标志决定表达式是否将文本视作单独的行处理,是否区分大小写,或者是否查找所有匹配项。
- 全局标志 : /…/g:全局标志使表达式选中所有匹配项,如果不启用全局标志,那么表达式只会匹配第一个匹配项。
- 多行标志 /…/gm:正则表达式将所有文本视作一行。但如果我们使用了多行标志,它就会单独处理每一行。
- 忽略大小写标志/…/gmi:表达式不再大小写敏感,可以启用不区分大小写标志
-
贪婪匹配.*:正则表达式默认执行贪婪匹配。这意味着匹配内容会尽可能长。
它匹配任何以 r 结尾的字符串,以及前面带有该字符串的文本,但它不会在第一个 r 处停止匹配。 文本:ber beer beeer beeeer 正则:/.*r/
-
懒惰匹配.*?:与贪婪匹配不同,懒惰匹配在第一次匹配时停止。
在 * 之后添加 ?,将查找以 r 结尾且前面带有任意字符的第一个匹配项。这意味着本次匹配将会在第一个字母 r 处停止。 文本:ber beer beeer beeeer 正则:/.*?r/
三、使用案例
-
示例:^.{m,n}$
匹配固定长度内容:^.{n}$,匹配任意开头但是长度n的内容 匹配最小长度内容:^.{m,}$,匹配任意开头但是长度不低于m的内容 匹配区间长度内容:^.{m,n}$,匹配任意开头但是长度在[m,n]之间的内容
-
示例:.*匹配
在正则表达式的末尾添加 .* 来匹配以 how to write 开头的表达式,并匹配后面的所有内容。 正则1:^how to write 正则2:how to write.* 在两个 .* 之间写上我们要查找的字段,以匹配包含该字段的所有的内容。例如匹配包含buy的内容 正则:.*buy.* 在.*\.和$之间加入想要作为结尾的字段,可以匹配以.XX格式结尾的内容,例如匹配.html文件 正则:.*\.html$
-
匹配http、https
匹配http或者https 正则1:^http 或者 ^(http|https)【仅作为开头】 正则2:http.*【不限于开头】 匹配非https即只要http 正则:http[^s].* URL:^http://([\w-]+\.)+[\w-]+(/[\w-./?%&=]*)?$
-
域名
域名:[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+\.?
-
邮箱Email
Email地址:^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$
-
手机号
手机号码:^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}$ 电话号码("XXX-XXXXXXX"、"XXXX-XXXXXXXX"等格式):^(\(\d{3,4}-)|\d{3.4}-)?\d{7,8}$ 国内电话号码(0511-4405222、021-87888822):\d{3}-\d{8}|\d{4}-\d{7}
-
身份证
身份证号(15位、18位数字),最后一位是校验位,可能为数字或字符X:(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)
-
密码
强密码(必须包含大小写字母和数字的组合,不能使用特殊字符,长度8-10之间):^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])[a-zA-Z0-9]{8,10}$ 强密码(必须包含大小写字母和数字的组合,可以使用特殊字符,长度8-10之间):^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,10}$
-
QQ号
腾讯QQ号:[1-9][0-9]{4,} (腾讯QQ号从10000开始)
-
邮政编码
中国邮政编码:[1-9]\d{5}(?!\d) (中国邮政编码为6位数字)
-
Ipv4地址
IPv4地址:((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})(\.((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})){3}
-
其他
空白行的正则表达式:\n\s*\r (可以用来删除空白行) HTML标记的正则表达式:<(\S*?)[^>]*>.*?|<.*? /> 首尾空白字符的正则表达式:^\s*|\s*$或(^\s*)|(\s*$) (可以用来删除行首行尾的空白字符(包括空格、制表符、换页符等等))