正则表达式学习笔记

本文最后更新于:2024年9月19日 晚上

0x00 学习资料

Learn Regex the Easy Way

正则表达式30分钟入门教程

正则表达式在线测试工具

轻松学习正则表达式

0x01 什么是正则表达式

维基上解释如下:

正则表达式(英语:Regular expression,常简写为regex、regexp),又称规律表达式正则表示式正则表示法规则表达式常规表示法,是计算机科学计算机科学)概念,用简单字符串来描述、匹配文中全部匹配指定格式的字符串字符串,现在很多文本编辑器文本编辑器都支持用正则表达式搜索、取代匹配指定格式的字符串。

个人理解:

正则表示式是一种用来描述字符串匹配模式的语法,使用正则表达式可以从字符串中找到符合匹配模式的结果。这里的匹配模式是指某种自定的规则,该规则描述了你想要的结果在整个字符串中出现的规律。使用正则表达式就类似在windows平台下使用的通配符*、?,但是其功能要强大得多,同时语法也丰富得多。

0x02 基本匹配

最基本的匹配就是输入什么就匹配什么, 例如:一个正则表达式 the,它表示一个规则:由字母t开始,接着是h,再接着是e

正则表达式是大小写敏感的,所以the不会匹配The

“the” => The fat cat sat on the mat.

PS:书写正则表达式时,通常会将模式的语法写在/pattern/两个斜杠之间,用来标识其使用正则表达式

0x03 元字符

在基本匹配中,有些字符无法通过基本匹配的方式直接匹配,这些字符是元字符。元字符不代表他们本身的字面意思,他们都有特殊的含义。以下是一些元字符的介绍:

元字符 描述
. 句号匹配任意单个字符除了换行符。
[ ] 字符类。匹配方括号内的任意字符。
[^ ] 否定字符类。匹配除了方括号里的任意字符
* 匹配>=0个重复的在*号之前的字符。
+ 匹配>=1个重复的+号前的字符。
? 标记?之前的字符为可选.
{n,m} 匹配num个大括号之前的字符或字符集 (n <= num <= m).
(xyz) 字符集,匹配与 xyz 完全相等的字符串.
| 或运算符,匹配符号前或后的字符.
\ 转义字符,用于匹配一些保留的字符 `[ ] ( ) { } . * + ? ^ $ \
^ 从开始行开始匹配.
$ 从末端开始匹配.

-1- 点运算符.

点运算符表示任意单个字符,这里要注意两点,

  • 点运算符代表至少有一个字符,也就是点运算符至少是占一位的
  • 点运算符不匹配换换行符\r\n,要匹配全体字符,要使用(.|\r|\n)

“.ar” => The car parked in the garage.

-2- 字符类[]

方括号用来指定一个字符类,字符类表示的是该集合中的任意一个元素,无论字符类中包含了多少个字符,在匹配时也只占一位。

“[Tt]he” => The car parked in the garage.

在字符类中,大部分元字符是失效的,这些元字符在方括号内只表示它们字符本身,但是-^\有其他含义。

  • -表示一个字符范围,指定从其前一位的ASCII值到其后一位的ASCII值的中间的全部字符,常用的有[A-Z]表示全部大写字母,[a-z]表示全部小写字母,[0-9]表示全部数字。

  • 如果想要表示-本身,可以将其放在字符类的第一位或者最后一位,如果一定要将其放在字符类的两个字符中间,可以使用转义字符\来表示其本身。

  • 表示转义字符\本身在字符类内依然要用\\来表示。

-3- 否定字符类[^]

否定字符类就是反选字符类中的元素,也就是字符类中的元素都排除掉,和字符类一样,否定字符类也是只占一位的。

否定字符类也是代表的也是一个集合中的某一个元素,只是该集合是通过在全部字符集中排除掉一部分得到的。

其他元字符在否定字符类的含义与在元字符内是一样的,如果想表示^字符,并且一定要将其放在字符类的第一位,可以使用转义字符来表示

“[^c]ar” => The car parked in the garage.

-4- 重复次数

表示重复次数的元字符有三个,分别是

  • *号

    匹配在*号之前出现的字符0次及0次以上(大于等于0次),与点运算符连用.*可以匹配所有字符串

    “[a-z]“ => T*he car parked in the garage

  • +号

    匹配在+号之前出现的字符1次及1次以上(大于等于1)

    “c.+t” => The fat cat sat on the mat.

  • ?号

    匹配在?号之前出现的字符可能出现也可能不出现(0次或1次)

    “[T]?he” => The car is parked in the garage.

以上三种符号均可以与字符类以及否定字符类连用

-5- 自定义重复次数{}

{} 是一个量词,常用来限定一个或一组字符可以重复出现的次数。

例如, 表达式 [0-9]{2,3} 匹配最少 2 位最多 3 位 0~9 的数字。?号等价于{0,1}

可以省略第二个参数。 例如,[0-9]{2,} 匹配至少两位 0~9 的数字。*号等价于{0,}+号等价于{1,}

如果逗号也省略掉则表示重复固定的次数。 例如,[0-9]{3} 匹配3位数字

-6- 字符集()

字符集是一组写在 () 中的子模式。() 中包含的内容将会被看成一个整体。例如, 表达式 (ab)* 匹配连续出现 0 或更多个 ab。如果没有使用 () ,那么表达式 ab* 将匹配连续出现 0 或更多个 b 。再比如之前说的 {} 是用来表示前面一个字符出现指定次数。但如果在 {} 前加上特征标群 () 则表示整个标群内的字符重复 N 次。

-7- 或运算符|

或运算符就是表示或者的意思,表示运算符前后元素二选其一,但是二者必须选其一。或运算符|的优先级最低

“(T|t)he|car” => The car is parked in the garage.

-8- 转义字符\

转义字符与其在C语言中的用法很像,反斜线 \ 在表达式中用于转码紧跟其后的字符。对于特殊字符 { } [ ] / \ + * . $ ^ | ? 这些,如果想要表达其本身字符的含义则要在其前面加上反斜线 \

对于一些控制字符,如回车,空格之类的,也需要使用转义字符加字母来表示;此外,正则表达式还定义了一些字符集的简写,也需要用到转义字符

简写 描述
\w 匹配所有字母数字,等同于 [a-zA-Z0-9_]
\W 匹配所有非字母数字,即符号,等同于: [^\w]
\d 匹配数字: [0-9]
\D 匹配非数字: [^\d]
\s 匹配所有空格字符,等同于: [\t\n\f\r\p{Z}]
\S 匹配所有非空格字符: [^\s]
\b 匹配单词的开始或结束
\B 匹配不是单词开头或结束的位置
\f 匹配一个换页符
\n 匹配一个换行符
\r 匹配一个回车符
\t 匹配一个制表符
\v 匹配一个垂直制表符
\p 匹配 CR/LF(等同于 \r\n),用来匹配 DOS 行终止符

-9- 锚点

锚点有两个^$,锚点可以规定匹配位置,^是从头指定开头,$指定结尾

例如,^(T|t)he 匹配以 Thethe 开头的字符串。

“^(T|t)he” => The car is parked in the garage.

例如,(at\.)$ 匹配以 at. 结尾的字符串。

“(at.)$” => The fat cat. sat. on the mat.

0x04 零宽断言

前面的大部分语法都是用来描述用来想要匹配本身是怎么样的,但是有时我们还希望描述被匹配到的字符串的位置,这时就需要用到零宽断言。零宽断言与前面的^$\b\B类似,都是用于描述被匹配模式的位置信息的,可以用来控制想要的字符串前后需要有或者不能有什么。

之所以叫零宽断言,可能是因为该语法本身不参与匹配,只用于限定想要匹配的字符串的位置,所以其宽度为零。

零宽断言的支持和正则引擎有关,有些引擎不支持零宽断言。这里的几种断言的英文名其实比中文名更能够表明其含义。

  • (?=exp)零宽正向先行断言(lookahead)
  • (?!exp)零宽负向先行断言(negative lookahead)
  • (?<=exp)零宽正回顾后发断言(lookbehind)
  • (?<!exp)零宽负回顾后发断言(negative lookbehind)

-1- 零宽正向先行断言(lookahead)

(?=exp),它断言自身出现的位置的后面能匹配表达式exp

例如,\b\w+(?=ing\b),就会匹配以ing结尾的单词前面部分,需要注意,零宽断言自己断言本身是不参与匹配的

“\b\w+(?=ing\b)” => I’m singing while you’re dancing

-2- 零宽正回顾后发断言(lookbehind)

(?<=exp),它断言自身出现的位置的前面能匹配表达式 exp。比如(?<=\bre)\w+\b会匹配以 re 开头的单词的后半部分(除了 re 以外的部分),例如在查找 reading a book 时,它匹配 ading。

“(?<=\bre)\w+\b” => reading a book

-3- 零宽负向先行断言(negative lookahead)

(?!exp),与零宽正向先行断言相反,它断言的是此位置的后面不能匹配表达式 exp。

例如:\d{3}(?!\d)匹配三位数字,而且这三位数字的后面不能是数字;\b((?!abc)\w)+\b匹配不包含连续字符串 abc 的单词。

-4- 零宽负回顾后发断言(negative lookbehind)

(?<!exp),同理,零宽负回顾后发断言也就指断言位置的前面不能出现表达式exp

例如:(?<![a-z])\d{7}匹配前面不是小写字母的七位数字。

0x05 修饰符(标记)

标记不写在正则表达式里,标记位于表达式之外,格式为/pattern/flags

-1- 修饰符g

global - 全局匹配,g 修饰符可以查找字符串中所有的匹配项。默认情况下(不带g),正则匹配会在找到第一个结果时停止,如果加上修饰符g,则会查找整个字符串,找到所有的匹配项。

-2- 修饰符i

ignore - 不区分大小写,i修饰符指定匹配时不区分大小写

-3- 修饰符m

multi line - 多行匹配,修改锚点元字符^$的含义,使其锚定为每行的开头和结尾。

“/.at(.)?$/“ => The fat
cat sat
on the mat.

“/.at(.)?$/gm” => The fat
cat sat
on the mat.

-4- 修饰符s

Singleline - 单行匹配,修改.元字符的含义,使其可以匹配所有的字符(包括\n换行符),在这种模式下,一篇文章可以被看作一行字符串,换行符\n也只是该行中的一个字符罢了。

需要注意的是,单行模式与多行匹配是可以同时使用的,它们二者并不冲突,因为它们针对的元字符都是不同的,同时使用这两个修饰符,就只是同时修改了^ $ .的含义。

0x06 贪婪和懒惰

通常情况下,正则匹配时会选择匹配尽可能多的字符,这中匹配策略被称为贪婪匹配。如果我们希望匹配时匹配最少的字符,就需要用?将匹配策略换为懒惰匹配,?添加在重复次数元字符的后面。

来看一个例子:aabbcb,使用a.*b匹配时,会匹配所有的字符,也就是aabbcb,但是如果使用懒惰匹配a.*?b,则会匹配aab(字符1-3)和ab(字符2-3)。

这里要注意的是,为什么懒惰匹配的结果不只是ab(字符2-3)呢,这时因为正则匹配中有一条规律的优先级比贪婪和懒惰要高:最先开始的匹配拥有最高的优先权,由于第一个a最先匹配,所以其拥有最高的优先级,因此可以不受贪婪和懒惰策略的影响。

懒惰限定符 说明
*? 重复任意次,但是尽可能少重复
+? 重复1次或更多次,但是尽可能少重复
?? 重复0次或1次,但是尽可能少重复
{n,m}? 重复n到m次,但是尽可能少重复
{n,}? 重复n次或更多次,但是尽可能少重复

-END-


正则表达式学习笔记
https://goooforward.github.io/blog/2023/10/31/study/正则表达式学习笔记/
作者
tangyuwei
发布于
2023年10月31日
许可协议