正则表达式入门笔记

正则表达式入门笔记

极客时间正则表达式入门课程笔记

正则常用的功能:校验数据有效性、查找符合要求的文本、对文本进行切合和替换。

元字符

元字符是正则的基本单元。它是正则表达式中具有特殊意义的专用字符。

元字符
分类 备注
特殊单字符 .任意字符(换行除外)
\d 任意数字 \D 任意非数字
\w 任意字母数字下划线 \W任意非字母数字下划线
\s 任意空白符 \S 任意非空白符
空白符 \r 回车符
\n 换行符
\f 换页符
\t 制表符
\v 垂直制表符
\s 任意空白符
量词 * 含义:0到多次
+ 含义:1到多次
? 含义:0到1次
{m} 含义:出现m次
{m,} 含义:出现至少m次
{m,n} 含义:m到n次
范围 | 或,如ab|bc代表ab或bc
[...] 多选一,括号中任意单个元素
[a-z] 匹配a到z之间任意单个元素\n (按ASCII表,包含a,z)
[^...] 取反,不能是括号中的任意单个元素
### 三种模式

贪婪模式、非贪婪模式和独占模式。

贪婪模式:尽可能进行最大长度匹配。正则的量词默认是使用的贪婪模式。

非贪婪模式:匹配长度最小满足要求的。在量词后边加上?

独占模式:类似贪婪模式,会尽可能多的去匹配,不回溯。匹配过程中独占模式不会交还已经匹配上的字符,如果匹配失败就结束。在量词后边加+

举个例子解释一下什么是回溯,当时我也是看了好久才看明白。

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}) 日期是第一个分组 时间是第二个分组。

不保存子组

在括号里使用?:不保存子组。不保存子组会提高正则性能,但是之后不能再利用括号中的值

括号嵌套

在复杂的括号嵌套中想要知道某个括号是第几个分组时怎么办?其实方法很简单,数左括号是第几个,就是第几个分组。

日期分组编号是1,时间分组编号是5,年是2。

分组引用

知道了分组应用的编号,大部分情况,我们可以使用“反斜杠 + 编号”的方式进行引用。不同编程语言查找和替换的引用方式:

编程语言 查找时引用方式 替换时引用方式
Java \number 如\1 $number 如$1
JavaScript $number 如$1 $number 如$1
Go 官方包不支持 官方包不支持
Python \number 如\1 \number 如\1

分组引用在查找中使用

如果我们要查找文中重复出现的单词 可以使用\w+来表示一个单词,那么使用\w+ \1就是这个正则了。

四种匹配模式

不区分大小写模式、点号通配模式、多行模式和注释模式。

不区分大小写模式

正则不区分英文字母的大小写,放在正则的前边。

修饰符:(?i)

修饰符在括号内作用范围是这个括号内的正则,不是整个正则。

点号通配模式

又叫单行匹配模式,改变的是点号的匹配行为,让其可以匹配任何字符,包括换行。

修饰符:(?s)

多行匹配模式

修饰符:(?m)

通常情况下,^匹配字符串的开头,$匹配字符串的结尾。

场景:日志以时间开头,打印堆栈占用了多行,可以使用多行匹配模式,在日志中匹配到以时间开头的每一行日志。

注释模式

就是给正则加注释,更容易阅读和维护。

修饰符:(:# xxx)

断言

用于匹配位置,而不是内容本身。常见的断言:单词边界、行的开始或结束、环视。

单词边界

\b 匹配单词边界。

例如,精准匹配单词 \b\w+\b

行的开始/结束

  • ^ 匹配行的开始。多行模式时,可以匹配任意行开头
  • $ 匹配行的结束。多行模式是,可以匹配任意行结束
  • \A 仅匹配整个字符串的开始,不支持多行模式
  • \Z 进匹配整个字符串的结束,不支持多行模式

环视

匹配前后要满足某种规则。

正则 名称 含义 示例
(?<=Y) 肯定逆序环视 左边是Y (?<=\d)X 匹配左边是数字的X
(?<!Y) 否定逆序环视 左边不是Y (?<!\d)th 匹配左边不是数字的th
(?=Y) 肯定顺序环视 右边是Y six(?=\d) 匹配右边是数字的six
(?!Y) 否定顺序环视 右边不是Y six(?!\d) 匹配右边不是数字的six

左尖括号代表看左边,没有尖括号看右边,叹号是非的意思。

左边不是数字,右边也不是数字的6位数:(?<!\d)[1-9]\d{5}(?!\d)

环视中虽然又括号,但是不会保存成子组。保存成子组的一般是匹配到的文本内容,后续用于替换等操作,而环视是表示对文本左右环境的要求,即环视只是匹配位置,不匹配文本内容。

常见问题及解决方案

数字

使用字符组、量词就能解决

  • 数字在正则中可以使用\d或者[0-9]来表示
  • 连续的多个数字使用\d+或[0-9]+
  • n位数据,可以使用\d
  • 至少n为数据,可以使用\d
  • m-n数字,可以使用\d

正数,负数和小数

如果希望正则能匹配到比如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)<title>.*?</title>来进行匹配。在提取引号里面的内容时,可以使用[A"]+,方括号里面的内容时,可以使用[^>]+等方式。

posted @ 2021-07-07 16:18  ChiZng  阅读(97)  评论(0)    收藏  举报