正则表达式

时间:2025-02-14 21:22:50

多种匹配模式

实例描述

[Pp]ython 匹配 “Python” 或 “python”。
rub[ye] 匹配 “ruby” 或 “rube”。
[abcdef] 匹配中括号内的任意一个字母。
[0-9] 匹配任何数字。类似于 [0123456789]。
[a-z] 匹配任何小写字母。
[A-Z] 匹配任何大写字母。
[a-zA-Z0-9] 匹配任何字母及数字。
[^au] 除了au字母以外的所有字符。
[^0-9] 匹配除了数字外的字符。

实例 描述
. 匹配除 “\n” 之外的任何单个字符。要匹配包括 ‘\n’ 在内的任何字符,
请使用象 ‘[.\n]’ 的模式。
? 匹配一个字符零次或一次,另一个作用是非贪婪模式
+ 匹配1次或多次
* 匹配0次或多次
\b 匹配一个长度为0的子串
\d 匹配一个数字字符。等价于 [0-9]。
\D 匹配一个非数字字符。等价于 [^0-9]。
\s 匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [\f\n\r\t\v]。
\S 匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。
\w 匹配包括下划线的任何单词字符。等价于’[A-Za-z0-9_]’。
\W 匹配任何非单词字符。等价于 ‘[^A-Za-z0-9_]‘。

一、入门

1、字符

输入 code就可以匹配所有包含code的数据

2、字符组

字符组([])允许匹配一组可能出现的字符。
[Pp]既可以匹配大写的P也可以匹配小写的p

3、区间

有一些常见的字符组非常大,比如,我们要匹配任意的数字,如果依照上述代码,每次我们都需要使用[0123456789]。

但是这样好吗?

如果要匹配从a-z的字母呢?我想你肯定不愿意从a写到z了!

为了适应这一点,正则表达式引擎在字符组中使用连字符(-)代表区间,依照这个规则,我们可以总结出三点:

要匹配任意数字可以使用[0-9];
如果想要匹配所有小写字母,可以写成[a-z];
想要匹配所有大写字母可以写成[A-Z]。
[]字符组中可以放多个条件例如,想要匹配数字的小写字母可以这样写:[0-9a-z]

4、快捷匹配数字和字母

如果想要匹配所有的字母,会使用[A-Za-z],要匹配数字会使用[0-9]

还有没有更简洁的方式呢?

正则表达式引擎提供了一些快捷方式如:\w 可以与任意单词字符匹配。

当我们想要匹配任意数字的时候也可以使用快捷方式\d,d即digit数字的意思,等价于[0-9]。

5、匹配特殊字符

正则表达使用了 - 号代表了区间,但是我们有时候需要匹配的符号就是 -号,该怎么办呢?

这个时候我们需要对-号进行转义操作,即 -。

在正则中使用 \ 就可以进行对特殊符号进行转义,对 - 进行转义就可以表示为 -,即 - 就代表了 - 号本身。

转义符 \ 也适用于其他的符号,例如匹配圆括号可以使用 (

5、取反

到目前为止,我们定义的字符组都是由可能出现的字符定义,不过有时候我们可能希望根据不会出现的字符定义字符组。
可以通过在字符数组开头使用 ^ 字符实现取反操作,从而可以反转一个字符组(意味着会匹配任何指定字符之外的所有字符)。
这里的 n[^e] 的意思就是n后面的字母不能为 e。

6、快捷方式取反

快捷方式也可以取反,例如对于\w的取反为\W,将小写改写成大写即可,其他快捷方式也遵循这个规则。

7、匹配空白

\s快捷方式可以匹配空白字符,比如空格,tab、换行等。

8、单词边界

\b 匹配的是单词的边界,例如,\bmaster\b 就仅匹配有边界的master单词。

9、开始和结束

正则表达式中 ^指定的是一个字符串的开始,$指定的是一个字符串的结束。

10、任意字符

.字符代表匹配任何单个字符,它只能出现在方括号以外。

值得注意的是: .字符只有一个不能匹配的字符,也就是换行符(\n),不过要让.字符与换行符匹配也是可以的,以后会讨论。

11、可选字符

有时,我们可能想要匹配一个单词的不同写法,比如color和colour,或者honor与honour。

这个时候我们可以使用 ? 符号指定一个字符、字符组或其他基本单元可选,这意味着正则表达式引擎将会期望该字符出现零次或一次。

/honou?r/g

在这里 u? 表示u是可选的,即可以出现也可以不出现,可以匹配的是 honor 和 honour 。
通过这个案例可以知道?的作用就是匹配它之前的字符0次或1次。

12、重复

  1. 重复字符:在一个字符组后加上{N} 就可以表示在它之前的字符组出现N次。

  2. 重复区间:有时候,我们不知道具体要匹配字符组要重复的次数,比如身份证有15位也有18位的。这里重复区间就可以出场了,语法:{M,N},M是下界而N是上界。

  3. 贪婪模式:\d{3,4} 既可以匹配3个数字也可以匹配4个数字,不过当有4个数字的时候,优先匹配的是4个数字,这是因为正则表达式默认是贪婪模式,即尽可能的匹配更多字符,而要使用非贪婪模式,我们要在表达式后面加上 ?号。

  4. 开闭区间:有时候我们可能遇到字符组的重复次数没有边界,闭区间不写即可表示匹配一个或无数个。

  5. 速写:还可以使用两个速写字符指定常见的重复情况,可以使用 + 匹配1个到无数个,使用 *代表0个到无数个。

    即:+等价于{1,},*等价于{0,}。

二、进阶

1、分组

介绍:在正则表达式中提供了一种将表达式分组的机制,当使用分组时,除了获得整个匹配。还能够在匹配中选择每一个分组。

要实现分组很简单,使用()即可。

/(\d{4})-(\d{7})/g
文本:
张三0731-8825951

分组有一个非常重要的功能——捕获数据。所以()被称为捕获分组,用来捕获数据,当我们想要从匹配好的数据中提取关键数据的时候可以使用分组。

(\d{4})(\d{7})就分别捕获了两段数据:
0731
8825951


或者条件:使用分组的同时还可以使用 或者(or)条件。

例如要提取所有图片文件的后缀名,可以在各个后缀名之间加上一个 |符号:

/(.jpg|.gif|.jpeg|.png)/g


非捕获分组有时候,我们并不需要捕获某个分组的内容,但是又想使用分组的特性。

这个时候就可以使用非捕获组(?:表达式),从而不捕获数据,还能使用分组的功能。

例如想要匹配两个字母组成的单词或者四个字母组成的单词就可以使用非捕获分组:

/\b(?:\w{2}|\w{4})\b/g


分组的回溯引用正则表达式还提供了一种引用之前匹配分组的机制,有些时候,我们或许会寻找到一个子匹配,该匹配接下来会再次出现。

例如,要匹配一段 HTML 代码,比如:

文本: 0123<font>提示</font>abcd

可能会编写出这样一段正则表达式:

/<\w+>.*</\w+>/g

这确实可以匹配,不过可能还有另一种情况,如果数据改成这样

文本:
0123<font>提示</bar>abcd
表达式:
/<\w+>.*</\w+>/g

在这里font 和 bar 明显不是一对正确的标签,但是我们编写的正则表达式还是将它们给匹配了,所以这个结果是错误的。

我们想让后面分组的正则也匹配font,但是现在所有形式的都会匹配。

那如果想让后面分组的正则和第一个分组的正则匹配同样的数据该如何做呢?

可以使用分组的回溯引用,使用\N可以引用编号为N的分组,因此上述例子的代码我们可以改为:

/<\w+>.*</\1/g

通过这个例子,可以发现 \1 表示的就是第一个分组,在这里第一个分组匹配的是 font 所以 \1 就代表font。

2、先行断言

介绍 :很多人也称先行断言和后行断言为环视,也有人叫预搜索,其实叫什么无所谓,重要的是知道如何使用它们!

先行断言和后行断言总共有四种:

正向先行断言
反向先行断言
正向后行断言
反向后行断言


  • 正向先行断言:(?=表达式),指在某个位置向看,表示所在位置右侧必须能匹配表达式

例如:

我喜欢你 我喜欢 我喜欢我 喜欢 喜欢你

如果要取出喜欢两个字,要求这个喜欢后面有你,这个时候就要这么写:喜欢(?=你),这就是正向先行断言

提取包含大小写字母的字符串 : (?=.?[a-z])(?=.?[A-Z]).+ 这段正则表达式规定了匹配的字符串中必须包含至少一个大写和小写的字母。

密码强度验证
请你编写正则表达式进行密码强度的验证,规则如下:

至少一个大写字母
至少一个小写字母
至少一个数字
至少8个字符

(?=.*?[a-z])(?=.*?[A-Z])(?=.*?[0-9]).{8,16}

反向先行断言(?!表达式)的作用是保证右边不能出现某字符。

例如: 我喜欢你 我喜欢 我喜欢我 喜欢 喜欢你

如果要取出喜欢两个字,要求这个喜欢后面没有你,这个时候就要这么写:喜欢(?!你),这就是反向先行断言。

3、后行断言

正向后行断言本小节只需要你记住一句话:先行断言和后行断言只有一个区别,即先行断言从左往右看,后行断言从右往左看。

正向后行断言:(?<=表达式),指在某个位置向左看,表示所在位置左侧必须能匹配表达式

例如:如果要取出喜欢两个字,要求喜欢的前面有我,后面有你,这个时候就要这么写:(?<=我)喜欢(?=你)。

反向后行断言:(?<!表达式),指在某个位置向左看,表示所在位置左侧不能匹配表达式

例如:如果要取出喜欢两个字,要求喜欢的前面没有我,后面没有你,这个时候就要这么写:(?<!我)喜欢(?!你)。