正则表达式学习记录

白衣黑月 / 62 / 2023-09-25 09:56:38

ChatGPT 可用网址,仅供交流学习使用,如对您有所帮助,请收藏并推荐给需要的朋友。
https://ckai.xyz

目录:
1、什么是正则
2、字符的理解
3、循环与重复
4、位置边界
5、子表达式
6、逻辑处理


1、什么是正则表达式

正则表达式本质上就是一个用于字符串模式匹配的工具,实现字符串的搜索和替换功能。

从其命名我们可以看出来,它是一种用于描述某种规则的表达式。

我们要学习的,就是其内部的搜索及替换的功能,至于其底层实现机制,并不深究。


2、字符的理解

正则表达式根本上是由各种字符组成的,其分为字符和元字符:

字符:就是基础的计算机字符编码,通常正则表达式里面使用的就是数字、英文字母。

元字符:就是用来表示特殊语义的字符。如^表示非,|表示或等。

正则表达式就是由这两种字符来组成各种实际的规则。

2.1 单个字符匹配

最简单的正则表达式就由数字和字母组成。如我想匹配 'banana'中的 'b' 这个字符,那我直接使用 /b/ 这个正则就行了,但是我们用 /a/ 就会匹配到所有的 'a' 字符。

但是如果我们想要匹配特殊的字符,如 '*' 这个字符本身是特殊字符,我们就需要转义字符 \ 来让特殊字符失去原本的含义。

/\*/  就是匹配 '*'这个字符

我们还可以用 \ 让原本不是特殊字符的字符,让其具有特殊的含义。如我们要匹配空格、换行、回退等符号的时候,可以用下面这张表记忆:

image.png

2.2 多个字符匹配

单个字符的匹配的一对一的,也就是说只能匹配一个结果,这显然不够用。正则表达式又引入了集合区间和通配符的方式实现一对多的匹配,即一个正则匹配多个不同的字符。

集合区间用 [] 表示,如:/[123]/ 能匹配字符串中的所有 1 2 3 字符。可以使用元区间 - 来表示集合区间的范围,如:/[0-9]/ 能匹配字符串中所有的数字,/[a-z]/ 则可以匹配所有的英文小写字母。

此外,正则表达式还衍生了一批用于匹配区间的简便特殊正则正则表达式,如下:

image.png


3、循环与重复

上面讲的是一对一和一对多的字符匹配,这里要讲的就是匹配字符的规则。

所谓的同时匹配多种字符,就是控制正则表达式中某字符的出现次数
出现次数分为:0次、1次、无数次、固定次数。

3.1 匹配0次或1次

元字符 '?' 表示匹配其前面的字符0次或1次,如:正则表达式 /colou?r/ 就能同时匹配字符串 'color' 和 'colour', 它表示 'u' 可以出现0次或1次。

3.2 匹配0次或多次

元字符 '*' 用来表示匹配0个字符或无数个字符.

3.3 匹配1次或多次

元字符 '+' 适用于要匹配同个字符出现1次或多次的情况。

3.4 匹配特定次数

元字符 '{}' 可以匹配特定次数的字符,如: /b{3}/ 表示我想匹配连续的3个b,它还有其他的衍生规则:

- {x}: x次

- {min, max}: 介于min次到max次之间

- {min, }: 至少min次

- {0, max}: 至多max次

最终,对循环与重复的匹配做个总结:

image.png


4、位置边界

所谓位置边界的匹配,就是在长文本字符串中,限制查找字符的位置条件。如我们只想在单词的开头或结尾查找字符等。

4.1 单词边界

单词边界就是只匹配单独的单词。比较常见的场景是在特定的文章或句子中匹配特定单词。如:

The cat scattered his food all over the room.

如果我用 /cat/ 去匹配文章中的单词,最终匹配还会多余地匹配到 'scattered' 这个单词。这时我们用特殊字符 \b 去包裹我们想设置边界的单词,如: /\bcat\b/,这样就能只匹配到 'cat' 单词了。

4.2 字符串边界

上面说的是匹配单词,但有时我们需要匹配一整条字符串,需要如何做呢?
元字符 '^' 可以用来匹配字符串的开头。而元字符 '$' 可以用来匹配字符串的末尾。

另外,要匹配整条字符串,必须要避免换行符的干扰,这就需要在正则表达式的最后加上字母 'm',这表示采用多行模式。

举个例子,我要匹配下面这段文字中的 ' I am the rain man' 这段文字:

until  that day,
he finally told me that,
' I am the rain man'

就要使用正则表达式 /^I am the rain man$/m.
除了多行模式,正则匹配还有其他的匹配模式,最终整理本部分内容如下:
image.png


5、子表达式

上面说的是最基础的字符匹配的内容,接下来要说的是正则子表达式。

其核心思想是把正则表达式复杂化。从简单到复杂的正则表达式演变通常要采用分组、回溯引用和逻辑处理的思想。利用这三种规则,可以推演出无限复杂的正则表达式。

5.1、分组

分组是子表达式的核心思想,其原理是:用'()'包含的正则表达式为一组子表达式,多个'()'包含的子表达式能组合成复杂的正则表达式。

5.2、 回溯引用

所谓回溯引用,指的是后面的子表达式复用前面已经匹配到的子字符串。可以理解为变量使用。其使用方法如:\1,\2 分别表示引用的第一个和第二个子表达式。而 \0 表示整个表达式。

回溯引用经常被用在替换字符串中,用 '$1' '$2' 表示要替换的字符串,如下:

let str = 'cad cae gg'

let str1 = str.replace(/(ca)d/g, '$1e')

console.log(str1);   //cae cae gg

其操作等价于:

let str1 = str.replace(/(ca)d/g, 'cae')

有时我们想限制回溯引用的适用范围,可以用前向/后向查找实现。

前向查找

是用来限制后缀的,通过(?=regex)的子表达式形式来限制后缀的内容,实现前向查找。

如:happy happily这两个单词,我想获得以happy开头的副词,就可以使用happ(?=ily)来匹配。

通俗理解,就是匹配到带 'ily'后缀的 'happ' 部分,具体看下面代码:

let str = 'happy happily'

let str1 = str.replace(/happ(?=ily)/, 'haha')

console.log(str1);   //happy hahaily

后向查找

后向查找(lookbehind)是通过指定一个子表达式,然后从符合这个子表达式的位置出发开始查找符合规则的字串。

如:apple people 这两个单词,我只想匹配apple的 ple,如何实现呢?

/(?<=app)ple/

其实其原理就是与前向相反,还是看那个例子:

let str = 'happy syppy'

let str1 = str.replace(/(?<=sy)ppy/, 'haha')

console.log(str1);   //happy syhaha

这里记住最关键的点: 括号里是条件,括号外才是要匹配和替换的内容!

最后回顾下这部分内容:
image.png


6、逻辑处理

所谓的逻辑处理,就是说三种逻辑关系,与 或 非。

其中只讨论或 与 非的关系。

或关系,通常给子表达式进行归类使用。比如,我同时匹配a,b两种情况就可以使用(a|b)这样的子表达式。

而非关系,分为两种情况:一种是字符匹配,另一种是子表达式匹配。
1)字符匹配: 表示非需要使用^这个元字符。只有在[和]内部使用的^才表示非的关系
2)子表达式匹配:非关系就要用到前面介绍的前向负查找子表达式(?!regex)或后向负查找子表达式(?<!regex)。

该部分总结如下:
image.png


最后,只要掌握了上面六个主要规则,就能应对大多数用正则表达式实现的匹配和替换问题了。


作者
白衣黑月
许可协议
CC BY 4.0
发布于
2023-09-25
修改于
2024-07-14
Bonnie image
尚未登录