「思维导图学前端 」初中级前端值得收藏的正则表达式知识点扫盲

如果启用了标志g,正则表达式会执行全局匹配,匹配到一个结果后不会立刻停止匹配,直到后续没有任何符合匹配规则的字符为止。

m

如果启用了标志m,正则表达式会执行多行匹配,^可以匹配每一行的开始或整个字符串的开始,而$可以匹配每一行的结束或整个字符串的结束。

示例如下:

/^\d+$/.test(‘123\n456’) // false

/^\d+$/m.test(‘123\n456’) // true

仍然可以匹配整个字符串

/^\d+\n\d+$/m.test(‘123\n45’) // true

位置限定符

=====

^

匹配字符的开始。比如必须以数字开始,可以这么写:

/^\d/

$

匹配字符的结束。比如必须以数字结束,可以这么写:

/\d$/

范围匹配

====

范围匹配是利用方括号[]实现的。

方括号[]用于范围匹配,也就是查找某个范围内的字符。比如[0-9]代表匹配数字,而[a-z]可以匹配小写字母a到z这26个字符中的任意一个。

如果要匹配不在方括号中的字符,可以在方括号中以^开头,比如[^0-9],用于匹配非数字,等价于\D

主要元字符

=====

.

匹配除换行符\n外的任意字符,如果要匹配任意字符,应该用/[.\n]*/

\s


匹配任意空字符,包括空格,制表符\t,垂直制表符\v,换行符\n,回车符\r,换页符\f\s等价于[ \t\v\n\r\f],注意方括号内第一个位置有空格。

这里也说下换行符和回车符的区别:

  • 换行符\n:光标下移一行,不回行首。

  • 回车符\r:光标回到行首,不换行。

\S


\S\s的反集 ,利用\s\S的这种互为反集的关系,我们就可以匹配任意字符,写法如下:

/[\s\S]/

\d


\d用于匹配数字,等价于[0-9]

\D


\D\d的反集,也就是匹配非数字,等价于[^0-9]

\w


\w用于匹配单词字符,包含0-9a-zA-z以及下划线_,等价于[A-Za-z0-9_]

\W


\W\w的反集,用于匹配非单词字符,等价于[^A-Za-z0-9_]

\n


\n是开发中经常遇到的换行符,而上面提到的\s是包含\n在内的。所以,能被\n匹配的字符,也一定能被\s匹配。

\b


\b用于匹配单词的边界,即单词的开始或结束。

一开始其实我不太能理解\b在正则表达式中的作用。

直到我自己试了一下这个案例

‘I love you’.match(/love/)

‘Iloveyou’.match(/love/)

这两个表达式都能匹配到结果"love"

但是有时候我们并不希望这样的字符串'Iloveyou'被匹配,因为它没有单词间的空格。

所以\b有了它存在的意义。看下面的例子:

‘I love you’.match(/\blove\b/)

‘Iloveyou’.match(/\blove\b/) // null

第一个表达式仍然可以正常匹配到结果,而第二个就无法匹配到结果了,这符合我们的预期。

有的人可能会说,那我可以用空格匹配啊。

‘I love you’.match(/ love /)

空格和\b在这种场景下还是有一点不一样的,这体现在match的结果上。

如果是用空格匹配,那么match的结果数组中的第一项就是" love ",是带了空格的,然而很多时候我们不希望在结果中得到空格,所以\b存在的意义也就比较明显了。

\B


\b相反,代表非单词边界。也就是说,使用\B匹配时,目标字符前或后不能是空格。

假设\B在前,比如

/\Babc/.test(‘111 abc’) // false

假设\B在后,比如

/abc\B/.test(‘abc 111’) // false

转义字符\


由于正则表达式中很多字符有特殊含义,比如(, ), \, [, ], +,如果你真的要匹配它们,必须加上转义符\

///.test(‘/’); // true

或 |


实现或的逻辑是比较简单的,正则表达式提供了|

要注意的是,|隔断的是其左右的整个子表达式,而不是单个普通字符。

所以,

/^ab|cd|ef$/.test(‘ab’) // true

/^ab|cd|ef$/.test(‘cd’) // true

/^ab|cd|ef$/.test(‘ace’) // false

还要注意的是,|具有从左到右的优先级,如果左侧的匹配上了,右侧的就被忽略了,即便右侧的匹配看起来更“完美”。

/a|ab/.exec('ab')得到的结果是

[“a”, index: 0, input: “ab”, groups: undefined]

量词

==

?

匹配前面的子表达式零次或一次

匹配前面的子表达式一次或多次

*

匹配前面的子表达式零次或任意次

{n,m}


匹配前一个普通字符或者子表达式最少n次,最多m次

{n,}


匹配前一个普通字符或者子表达式最少n次

{n}


匹配前一个普通字符或者子表达式n次

贪婪

贪婪匹配是尽可能多地匹配,如果能满足匹配条件,就尽可能侵占后面的匹配规则。

贪婪匹配是默认的,比如/\d?/会尽可能地匹配1个数字,/\d+//\d*/会尽可能地匹配多个数字。

举个例子,

‘123456789’.match(/^(\d+)(\d{2,})$/)

以上结果中捕获组的第一项是"1234567",第二项是"89"

为什么会这样呢?因为\d+是贪婪匹配,尽可能地多匹配,如果没有后面的\d{2,},捕获组第一项会直接是"123456789"。但是由于\d{2,}的存在,\d+会给\d{2,}留个面子,满足它的最小条件,即匹配2个数字,而\d+自己匹配7个数字。

非贪婪


非贪婪匹配是尽可能少地匹配,一般是在量词?, +, *之后再加一个?,表示尽可能少地匹配,把机会留给后面的匹配规则。

还是拿贪婪模式中那个例子举例,稍微改一下,\d+换成非贪婪模式\d+?

‘123456789’.match(/^(\d+?)(\d{2,})$/)

捕获组的第一项是"1",第二项变成了"23456789"

为什么会这样呢?因为在非贪婪模式下,会尽可能少匹配,把机会留给后面的匹配规则。

分组

==

分组在正则中是一个非常有用的神器,用圆括号()来包裹的内容就是一个分组,在正则中是这种表示形式:

/(\d*)([a-z]*)/

捕获组()


利用捕获组,我们能捕获到关键字符。

比如

var group = ‘123456789hahaha’.match(/(\d*)([a-z]*)/)

分组1用于匹配任意个数字,分组2用于匹配任意个小写字母。

那么我们在match方法的返回结果中就可以取到这两个分组匹配的结果,group[1]"123456789"group[2]"hahaha"

我们还可以在RegExp的静态属性$1~$9取得前9个分组匹配的结果。RegExp.$1"123456789"RegExp.$2"hahaha"。但是RegExp.$1~$9是非标准的,虽然很多浏览器都实现了,尽量不要在生产环境中使用。

这种捕获组的应用在字符串的replace方法中也是类似,不过在调用replace方法时,我们需要通过$1, $2, $n这种形式去引用分组。

“123456789hahaha”.replace(/(\d*)([a-z]*)/, “$1”) // “123456789”

利用$1,我们就可以把源字符串替换为分组1匹配到的字符串,也就是"123456789"

非捕获组(?😃


非捕获组是不生成引用的分组,它也由圆括号()包裹起来,不过圆括号中起头的是?:,也就是/(?:\d*)/这种形式。

还是改造下之前的例子来看下:

var group = ‘123456789hahaha’.match(/(?:\d*)([a-z]*)/)

由于非捕获组不生成引用,所以group[1]"hahaha";同样地,RegExp.$1也是"hahaha"

看到这里,我不禁也产生了疑问,既然我不需要引用非捕获组,那么非捕获组的意义何在?

思考了一阵后,我觉得非捕获组大概有这么一些优势和必要性:

  1. 与捕获组相比,非捕获组在内存上开销更小,因为它不需要生成引用

  2. 分组是为了方便加量词。我们虽然可以不生成引用,但是如果没有分组,就不太方便加给一组字符加量词。

‘1a2b3c…’.match(/(?:\d[a-z]){2,3}(.+)/)

引用\num


正则表达式中可以引用前面的具有引用的分组,通过\1\2这种形式可以实现引用前面的子表达式。

比如,我要匹配一个字符串,要求符合这样的规则:

字符串由单引号或双引号开头和结束,中间内容可以是数字,单词。

那我要保证的是首尾要么是单引号,要么是双引号,所以我的pattern写法可以是:

var pattern = /^(["'])[a-z\d]*\1$/

pattern.test(“‘perfect123’”) // true

pattern.test(‘“1perfect2”’) // true

零宽断言

====

说实话,一开始看零宽断言的概念和解释时,我真的完全不懂在说什么。

  • 零宽正向先行断言(?=)

  • 零宽负向先行断言(?!)

  • 零宽正向后行断言(<?=)

  • 零宽负向后行断言(<?!)

后面把词汇拆开来看,加入自己的理解,就慢慢有点懂了。

  • 零宽:zero width,断言作为必要条件进行匹配,但是不体现在匹配结果中。

  • 正向:positive,断言中的字符必须被匹配。

  • 负向:negative,断言中的字符不能被匹配。

  • 先行:lookahead,必须满足前方的条件,条件在前方,前方等同于右侧。

  • 后行:lookbehind,必须满足后方的条件,条件在后方,后方等同于左侧。

零宽正向先行断言(?=)


约束目标右侧必须存在指定的字符。

/123(?=a)/.test(‘123a’) // true

上面的例子约束了123右侧必须有a

零宽负向先行断言(?!)


约束目标右侧不能存在指定的字符。

/123(?!a)/.test(‘123a’) // false

上面的例子约束了123右侧不能有a,否则结果为false

零宽正向后行断言(<?=)


约束目标左侧必须存在指定的字符。

/(?<=a)123/.test(‘a123’) // true

上面的例子约束了123左侧必须有a

ES2018才支持零宽后行断言,具体见TC39 Proposals[2]

零宽负向后行断言(<?!)


约束目标左侧不能存在指定的字符。

/(?<!a)123/.test(‘a123’) // false

上面的例子约束了123左侧不能有a,否则结果为false

注:ES2018才支持此特性。

RegExp

======

说到正则表达式,就不得不提到RegExp对象。下面我们从原型方法,静态属性,实例属性等几个方面来认识下RegExp对象。

原型方法


RegExp.prototype.test

test()是我们平时最常用的正则方法,test()方法执行一个检索,用来查看正则表达式与指定的字符串是否匹配,返回一个布尔值truefalse

如果正则表达式设置了全局标志g,执行test()会改变RegExp.lastIndex属性,用于记录上次匹配到的字符的起始索引。连续执行test()方法,后续的执行将会从lastIndex处开始匹配字符串。这种情况下,如果test()无法匹配到结果,lastIndex就会重置为0

RegExp.prototype.exec

exec()相较于test()能得到更丰富的匹配信息,其结果是一个数组,数组的第0个元素是匹配到的字符串,第1~n个元素是圆括号()分组捕获的结果。

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)


完整版面试题资料免费分享,只需你点赞支持,动动手指点击此处就可免费领取了

前端实习面试的套路


回顾项目

往往在面试时,面试官根据你简历中的项目由点及面地展开问答,所以请对你做过的最好的项目进行回顾和反思。回顾你做过的工作和项目中最复杂的部分,反思你是如何完成这个最复杂的部分的。

面试官会重点问你最复杂的部分的实现方法和如何优化。重点要思考如何优化,即使你项目中没有对那部分进行优化,你也应该预先思考有什么优化的方案。如果这部分答好了,会给面试官留下很不错的印象。

重点在于基础知识

这里指的基础知识包括:前端基础知识和学科基础知识。

前端基础知识:html/css/js 的核心知识,其中 js 的核心知识尤为重要。比如执行上下文、变量对象/活动对象(VO/AO)、作用域链、this 指向、原型链等。

学科基础知识:数据结构、计算机网络、算法等知识。你可能会想前端不需要算法,那你可能就错了,在大公司面试,面试官同样会看重学生这些学科基础知识。
你可能发现了我没有提到React/Vue这些框架的知识,这里得说一说,大公司不会过度的关注这方面框架的知识,他们往往更加考察学生的基础。
这里我的建议是,如果你至少使用或掌握其中一门框架,那是最好的,可以去刷刷相关框架的面试题,这样在面试过程中即使被问到了,也可以回答个 7788。如果你没有使用过框架,那也不需要太担心,把重点放在基础知识和学科基础知识之上,有其余精力的话可以去看看主流框架的核心思想。

[外链图片转存中…(img-ef4C7uhJ-1713611392181)]

完整版面试题资料免费分享,只需你点赞支持,动动手指点击此处就可免费领取了

前端实习面试的套路


回顾项目

往往在面试时,面试官根据你简历中的项目由点及面地展开问答,所以请对你做过的最好的项目进行回顾和反思。回顾你做过的工作和项目中最复杂的部分,反思你是如何完成这个最复杂的部分的。

面试官会重点问你最复杂的部分的实现方法和如何优化。重点要思考如何优化,即使你项目中没有对那部分进行优化,你也应该预先思考有什么优化的方案。如果这部分答好了,会给面试官留下很不错的印象。

重点在于基础知识

这里指的基础知识包括:前端基础知识和学科基础知识。

前端基础知识:html/css/js 的核心知识,其中 js 的核心知识尤为重要。比如执行上下文、变量对象/活动对象(VO/AO)、作用域链、this 指向、原型链等。

学科基础知识:数据结构、计算机网络、算法等知识。你可能会想前端不需要算法,那你可能就错了,在大公司面试,面试官同样会看重学生这些学科基础知识。
你可能发现了我没有提到React/Vue这些框架的知识,这里得说一说,大公司不会过度的关注这方面框架的知识,他们往往更加考察学生的基础。
这里我的建议是,如果你至少使用或掌握其中一门框架,那是最好的,可以去刷刷相关框架的面试题,这样在面试过程中即使被问到了,也可以回答个 7788。如果你没有使用过框架,那也不需要太担心,把重点放在基础知识和学科基础知识之上,有其余精力的话可以去看看主流框架的核心思想。

  • 15
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值