极客时间正则表达式入门课程笔记
正则常用的功能:校验数据有效性、查找符合要求的文本、对文本进行切合和替换。
元字符
元字符是正则的基本单元。它是正则表达式中具有特殊意义的专用字符。
三种模式
贪婪模式、非贪婪模式和独占模式。
贪婪模式:尽可能进行最大长度匹配。正则的量词默认是使用的贪婪模式。
非贪婪模式:匹配长度最小满足要求的。在量词后边加上?
独占模式:类似贪婪模式,会尽可能多的去匹配,不回溯。匹配过程中独占模式不会交还已经匹配上的字符,如果匹配失败就结束。在量词后边加+
举个例子解释一下什么是回溯,当时我也是看了好久才看明白。
regex = "xy{1,3}yz"
text = "xyyz"
匹配过程:在匹配y{1,3}时会尽可能长的去匹配,所以匹配到xy后还会使用y去匹配下一个是否时y,因为现在才匹配到了一个y。继续匹配xyy,现在两个 y。继续用第三个y匹配,发现下一个不是y。匹配两个y。继续匹配正则下一个规则,吐出当前字符z,接着用正则中的y去匹配吐出来的当前字符z,发现不匹配。向前回溯匹配一个y,然后继续匹配下一个规则匹配xy{1,3}yz中的y,然后匹配z。
非贪婪模式匹配
regex = "xy{1,3}?yz"
text = "xyyz"
匹配过程:在匹配y{1,3}?时会尽可能短的去匹配,所以当匹配到xy后使用正则中的y去匹配下一个字符,发现匹配。继续匹配z,发现匹配
独占模式匹配
regex = "xy{1,3}+yz"
text = "xyyz"
匹配过程:匹配到xyy,继续用y去匹配z匹配不上,然后继续正则中xy{1,3}+yz中的y的匹配。发现y和当前字符z不匹配,不回溯。导致匹配失败。
分组和引用
分组和编号
括号在正则中可以用于分组,被括号括起来的部分“子表达式”会被保存为一个自组。
第几个括号就是第几个分组。
例如将2021-06-21 21:24:05
提取出日期和时间(\d{4}-\d{2}-\d{2}) (\d{2}:\d{2}:\d{2})
日期是第一个分组 时间是第二个分组。
不保存子组
在括号里使用?:不保存子组。不保存子组会提高正则性能,但是之后不能再利用括号中的值
括号嵌套
在复杂的括号嵌套中想要知道某个括号是第几个分组时怎么办?其实方法很简单,数左括号是第几个,就是第几个分组。
[图片上传失败...(image-c527fe-1624547030265)]
日期分组编号是1,时间分组编号是5,年是2。
分组引用
知道了分组应用的编号,大部分情况,我们可以使用“反斜杠 + 编号”的方式进行引用。不同编程语言查找和替换的引用方式:
编程语言 | 查找时引用方式 | 替换时引用方式 |
---|---|---|
Java | \number 如\1 | 1 |
JavaScript | 1 | 1 |
Go | 官方包不支持 | 官方包不支持 |
Python | \number 如\1 | \number 如\1 |
分组应引用在查找中使用
如果我们要查找文中重复出现的单词 可以使用\w+
来表示一个单词,那么使用\w+ \1
就是这个正则了。
[图片上传失败...(image-13aa71-1624547030265)]
四种匹配模式
不区分大小写模式、点号通配模式、多行模式和注释模式。
不区分大小写模式
正则不区分英文字母的大小写,放在正则的前边。
修饰符:(?i)
修饰符在括号内作用范围是这个括号内的正则,不是整个正则。
点号通配模式
又叫单行匹配模式,改变的是点号的匹配行为,让其可以匹配任何字符,包括换行。
修饰符:(?s)
多行匹配模式
修饰符:(?m)
通常情况下,^匹配字符串的开头,$匹配字符串的结尾。
场景:日志以时间开头,打印堆栈占用了多行,可以使用多行匹配模式,在日志中匹配到以时间开头的每一行日志。
注释模式
就是给正则加注释,更容易阅读和维护。
修饰符:(:# xxx)
断言
用于匹配位置,而不是内容本身。常见的断言:单词边界、行的开始或结束、环视。
单词边界
\b 匹配单词边界。
例如,精准匹配单词 \b\w+\b
行的开始/结束
- ^ 匹配行的开始。多行模式时,可以匹配任意行开头
- $ 匹配行的结束。多行模式是,可以匹配任意行结束
- \A 仅匹配整个字符串的开始,不支持多行模式
- \Z 进匹配整个字符串的结束,不支持多行模式
环视
匹配前后要满足某种规则。
正则 | 名称 | 含义 | 示例 |
---|---|---|---|
(?<=Y) | 肯定逆序环视 | 左边是Y | (?<=\d)X 匹配左边是数字的X |
(? | 否定逆序环视 | 左边不是Y | (? |
(?=Y) | 肯定顺序环视 | 右边是Y | six(?=\d) 匹配右边是数字的six |
(?!Y) | 否定顺序环视 | 右边不是Y | six(?!\d) 匹配右边不是数字的six |
左尖括号代表看左边,没有尖括号看右边,叹号是非的意思。
左边不是数字,右边也不是数字的6位数:(?
环视中虽然又括号,但是不会保存成子组。保存成子组的一般是匹配到的文本内容,后续用于替换等操作,而环视是表示对文本左右环境的要求,即环视只是匹配位置,不匹配文本内容。
常见问题及解决方案
数字
使用字符组、量词就能解决
- 数字在正则中可以使用\d或者[0-9]来表示
- 连续的多个数字使用\d+或[0-9]+
- n位数据,可以使用\d{n}
- 至少n为数据,可以使用\d{n,}
- m-n数字,可以使用\d{m,n}
正数,负数和小数
如果希望正则能匹配到比如3,3.14,-3.3,+2.7等数字,需要注意的是,开头的正负符号可能有,也可能没有,所以可以使用[-+]?来表示,小数点和后面的内容也不一定会有,所以可以使用(?:.\d+)?来表示,因此匹配正数、负数和小数的正则可以写成[-+]?\d+(?:.\d+)?。
- 非负整数,包含0和正整数,可以表示成[1-9]\d*|0
- 非正整数,包括0和负整数,可以表示成-[1-9]\d*|0
浮点数
可以使用[-+]?\d+(?:\.\d+)?
来表示
十六进制数
可以使用[0-9A-Fa-f]+
手机号码
身份证号码
第一代身份证:[1-9]\d{14}
第二代:[1-9]\d{14}(\d\d[0-9Xx])?
腾讯QQ号
目前QQ号不能以0开头,最长的有10位,最短的从10000(5位)开始。从规则上我们可以得知,首位是1-9,后面跟着是4到9位的数字,即可以使用[1-9][0-9]{4,9}
来表示。
中文字符
中文属于多字节Unicode字符,中文的码值范围是4E00-9FFF之间。
不同的语言是表示方式有一些差异,比如在Python,Java,JavaScript中,Unicode可以写成\u码值来表示,即匹配中文的正则可以写成[\u4E00-\u9FFF],如果在PHP中使用,Unicode就需要写成\u(码值)的样式。
IPv4地址
IPv4地址通常表示成27.86.1.226的样式,4个数字用点隔开,每一位范围是0-255,比如从日志中提取出IP,如果不要求那么精确,一般使用\d{1,3}(\.\d{1,3}){3}
就够了,需要注意点号需要转义。
精确:(?:1\d\d|2[0-4]\d|25[0-5]|0?[1-9]\d|0{0,2}\d)(?:\.(?:1\d\d|2[0-4]\d|25[0-5]|0?[1-9]\d|0{0,2}\d)){3}
。
网页标签
配对出现的标签,比如title,一般网页标签不区分大小写,我们可以使用(?i)
来进行匹配。在提取引号里面的内容时,可以使用[A"]+
,方括号里面的内容时,可以使用[^>]+
等方式。