两小时学会 JS 正则表达式,终身不忘

1,517 阅读9分钟

版权声明:本人文章仅在掘金平台发布,请勿抄袭搬运,转载请注明作者及原文链接 🦉

阅读提示:网页版带有主题和代码高亮,阅读体验更佳 🍉

说两小时就两小时。

开门见山。

本篇文章每个规则都有一个练习题,建议大家在学习规则时在这个正则表达式练习网站上进行练习。

JS 中的正则

创建正则表达式

js 中内置了正则表达式对象 RegExp,我们要创建一个正则表达式,可以:

// 构造函数 new 创建
const regExp = new RegExp(pattern, modifiers)

// 字面量创建
const regExp = /12345/;

RegExp 接收两个参数,pattern 描述了表达式的模式,modifiers 是修饰符,用于执行区分大小写和全局匹配。

const regExp = new RegExp("\\w+");
const regExp = /\w+/;

构造函数创建时 pattern 是正则字符串,字面量创建时,pattern 是一个类似 /正则规则/ 表达式,是放在双斜杠里的。

modifiers 具体是三个值:

修饰符描述
i执行对大小写不敏感的匹配。
g执行全局匹配(查找所有匹配而非在找到第一个匹配后停止)。
m执行多行匹配。

可以这么使用:

// 两个参数都是字符串形式,修饰符可以多传
const regExp = new RegExp("\\w+", 'i');
const regExp = new RegExp("\\w+", 'g');
const regExp = new RegExp("\\w+", 'm');
const regExp = new RegExp("\\w+", 'igm');

const regExp = /\w+/i;
const regExp = /\w+/g;
const regExp = /\w+/m;
const regExp = /\w+/igm;

一般下,我们使用字面量的方式创建正则。

正则表达式实例上的方法与属性

和其他 js 对象一样,正则实例上也有一些方法给我们调用。

方法描述
exec检索字符串中指定的值。返回找到的值,并确定其位置
test检索字符串中指定的值。返回 true 或 false
toString返回正则表达式的字符串

exec 方法意为捕获,捕获字符串中的某些内容并作为返回值。举个例子,输入 1-10 格式,拿到第一位数、第二位数,for 循环生成这两位数之间所有自然正整数。那想拿到 - 两边的数字,就要利用 exec 方法。

test 方法意为检测,检测一个字符是否符合正则,返回 truefalse。一般我们 test 方法会用得比较多。

const regExp1 = new RegExp("12345");
const regExp2 = /12345/;

regExp1.exec('12345')
regExp2.test('12345')

类似数组字符串自带 length 一样,正则实例也自带一些属性。

属性描述
constructor返回一个函数,该函数是一个创建 RegExp 对象的原型
global判断是否设置了 "g" 修饰符
multiline判断是否设置了 "m" 修饰符
ignoreCase判断是否设置了 "i" 修饰符
source返回正则表达式的匹配模式
lastIndex用于规定下次匹配的起始位置

正则规则语法

切记:正则表达式中不要随意空格,空格也是会被当做字符处理!

在正则表达式中,有三种括号,()[]{},可以说,学会这三种括号,就学会了正则表达式。我们先从 [] 说起,() 理解上会难些,我们放在最后讲解。

直接字符匹配

问题:在以下字符串中匹配 2022 字符串。

你的答案:// ?

需要匹配的不能匹配的
2022年2202年
2022年10月2202年10月
2022年正则学习2202年正则学习

正确答案:/2022/

规则:直接字符匹配。

字符组:[]

问题:在以下字符串中匹配 Javajava 字符串。

你的答案:// ?

需要匹配的不能匹配的
Javajjva
javajvav

正确答案:/[Jj]ava/

规则[] 字符组。字符组的意思就是一个中括号,匹配 [] 里面的任意一个字符即可。在案例中我们的 java 有大写和小写,如果我们直接匹配 /java/ 或者 /Java/ 都是不够的,但是我们观察到这两个字符仅仅是首字母大写不同而已,那么只要兼容首字母大小写即可。写成 /javaJava/ 更是大错特错,因为这是直接字符匹配,匹配的是字符串中包含 javaJava 的字符,与题意不符。

扩展:匹配以下字符中的 Java,java,Jave,jAve。

需要匹配的不能匹配的
JavaJavv
javajana
javejavv
jAvejAee

正确答案:/[Jj][Aa]v[ae]/

字符组区间:-

问题:匹配以下字符中包含26个英文字母的字符。

你的答案:// ?

需要匹配的不能匹配的
123456789a123456789
12121332323v12121332323
6789098765x6789098765

正确答案:/\d*[a-zA-Z]/

规则区间。这里的 \d* 你要是不理解可以不管,后面会说。这题其实是规则2的延伸,如果我们要匹配的可选字符非常多,比如26个英文字母,匹配其中任意一个,难道要写 /[abcd...xyz]/ 吗?为了简化这种表达,引入 -[] 中表达区间的意义。/[a-z]/ 表示小写26个英文字母,[A-Z] 则表示大写,且可以连写 [a-zA-Z]。还可以匹配数字范围:[0-9a-zA-Z]

字符组取反:[^]

问题:在以下字符串中匹配不包含小写字母的字符串。

你的答案:// ?

需要匹配的不能匹配的
12345ASDFGHJ123456asdf
WERTGBJNghhhiuiio
1234567ddss1234567

正确答案:/[^a-z]/

规则[^],字符组取反。有时候我们是想要匹配某个字符,但是我们也有想它不匹配的情况。

扩展:匹配 后面不包含 的字符。

需要匹配的不能匹配的
正式正则
正反正则表达式
正确正则匹配

答案:/正[^则]/

数量匹配符:{}

问题:匹配以下含有 jjjjj 的字符。

你的答案:// ?

需要匹配的不能匹配的
jjjjjavajava
jjjjjavaajjava
jjjjjavaaajjjava
jjjjjavaaaajjjjava

正确答案:/j{5}ava{1,4}/

规则{}。表示数量,例如这个例子,{5} 表示 j 字符的出现5次,{1,4} 表示字符 a 出现的次数区间,在 1-4 之间(包含4)。当然了,如果这个字符出现次数没有上限,可以写成:{1,}

量词 {} 的另一种表达:+*

问题:匹配以下含有数字的字符。

你的答案:// ?

需要匹配的不能匹配的
123java
12121jjava
1212121jjjava
454664567jjjjava

正确答案:/\d*/

规则+,表示该字符至少出现一次,等同于 {1,}* 表示该字符出现0或无数次,等同于 {0,}。很多时候这种简写会带来不少便利,例如,配合任意字符 . 可以匹配任意字符任意次数 /.*/。例如我现在拷贝了一份 HTML,但是其中的 class 选择器我都要删除,我可以匹配出 /class=".*"/ 所有的 class 类从而删除它们。

分组符:()

问题:匹配以下特定文件 .jpg,.png,.mp3,.mp4。

你的答案:// ?

需要匹配的不能匹配的
image.jpgimage.jpeg
image.pngimage.img
music.mp3music.mu
movie.mp4movie.mo

正确答案:/.*\.(jpg|png|mp3|mp4)/

规则()。规则分组,类似 js 中的 (a + b) * c,将一组规则划为一个整体。在此题中,将所有可能出现的文件后缀作为一组。另外,| 表示 条件,不再单独讲解。

分组符配合 exec 捕获数据

在前面我们讲过,exec 可以捕获数据,所谓捕获数据,可能有点抽象。我们来举个例子:

问题:有一个输入框,用户输入形如 1-102-9 的数字,开发人员需要将 - 左右两侧的数字提取出来,做其他处理。

image.png

分组符 () 的作用就是将这些要捕获的数据标明出来。当然了,如果我们想要 () 的分组能力,但是又不想捕获数据,可以使用 (?:) 表达式。

转义符:\

问题:匹配下列左侧字符。

你的答案:// ?

需要匹配的不能匹配的
[]23456789
-[]-gfhdhfg
//[]--hfjfj5675

正确答案:/[\[\]]\-\/]/

规则\,转义字符。 正如上题所说,-[] 中表示区间,那我如果就是要匹配携带 - 的字符呢?这时候就需要 \,将这些在正则里有特殊含义的字符转换为普通字符。如果要匹配带 \ 的字符,就需要 \\,使用 \\ 进行转义。下面代码拆解本题正则:

/** [] 匹配任意一个字符,这是最外层 [] */
/[]/

/** 使用 \ 对 [] 进行转义,\[\] */
/[\[\]]/

/** 使用 \ 对 - 进行转义 */
/[\[\]]\-/

/** 使用 \ 对 / 进行转义 */
/[\[\]]\-\//

字母数字的快捷表达式:\w\d

问题:匹配以下仅包含数字和字母的字符。

你的答案:// ?

需要匹配的不能匹配的
12345ASDFGHJ!@^&*()
WERTGBJN)(*&^%%$)
1234567##$%^&*

正确答案:/\w/

规则:一些快捷方式,例如 \w\d\W\D...

快捷方式描述
\w与任意单词字符匹配,任意单词字符表示 [A-Z][a-z][0-9]_
\W\w 的取反
\d任意数字
\D\d 的取反

快捷方式有很多,先记住 \w\d 这两个常用的即可。

特殊字符:\n\t\r\s

问题:匹配以下含有空格的字符。

你的答案:// ?

需要匹配的不能匹配的
12345 ASDFGHJ!@^&*()
WERT GBJN)(*&^%%$)
1234 567##$%^&*

正确答案:/\s/

规则

字符描述
\s空白符
\n换行
\t制表符 tab
\r回车符

开始和结束:^$

问题:匹配以下1开头9结尾的数字。

你的答案:// ?

需要匹配的不能匹配的
1239189898
192878789
197878792675656

正确答案:/^1\d*9$/

规则^,在这里表示以什么字符开头,在 [] 的开头表示取反;$ 表示以哪个字符结尾。

任意字符:.

规则. 字符代表匹配任何单个字符,它只能出现在 [] 以外。值得注意的是 . 字符只有一个不能匹配的字符,也就是换行符 \n

可选字符:?

问题:匹配以下 java,jva。

你的答案:// ?

需要匹配的不能匹配的
javajav
jvajvav

正确答案:/ja?va/

规则?,在这里表示该字符可以没有,这里的 a 可有可无。

总结

正则表达式的学习,狭义上说就是对三种括号 ()[]{} 的学习。学会了这三种括号,也就是入了正则表达式的门。我们前面也补充了一些常用且重要的特殊字符,例如转义符 \、开始结束符 ^ $、数字符 \d、数字字母快捷符 \w、特殊字符 \n \t、量词快捷符 + * 等。熟记这几种字符,加上几遍练习,即可掌握正则表达式。下面来做一些练习。

练习1

问题:编写一个匹配手机号码的正则。

解析:手机号码是纯数字的,那么我们想到使用 \d 表示数字,手机号码都是1开头的,那么可以配合 ^ 使用。手机号码的第二位数,在3到9之间。另外,手机号码固定11位数,这里可以使用 {} 表示数字的出现次数。

答案/^1[3-9]\d{9}$/。网络上有些手机号码正则表达式第二位数将6排除在外,这是有问题的。在联通里有 166 的号码段,第二位数就是6。

练习2

问题:编写一个简易版匹配电子邮箱的正则。

解析:以 QQ 邮箱为例,一般长这样:12345678@qq.com。特点就是 @ 和域名 .com,主要就是四部分:

  • 12345678:第一部分
  • @:第二部分
  • qq:第三部分
  • .com:第四部分

接下来代码拆解下正则编写过程:

/** 
 * 名称部分可能是数字、字母、下划线、短横杠,
 * 不能是特殊字符,且必须出现至少1次
 */
/^[\w\-]+/

/** @ */
/^[\w\-]+@/

/** 邮箱服务商 */
/^[\w\-]+@[\w\-]+/

/** 域名 */
/^[\w\-]+@[\w\-]+\.[a-zA-Z]{2,5}$/

答案/^[\w\-]+@[\w\-]+\.[a-zA-Z]{2,5}$/

恭喜大家已经学完了正则表达式,不知道大家看完本篇文章后,是否已经熟练掌握了正则呢?希望大家不要光看不练,不然,看再多文章和视频都掌握不了正则的。