-
- (1)正则表达式初体验
-
(2)深入了解正则
-
- 字符类
-
重复
-
选择
-
分组与引用
-
指定匹配位置
-
修饰符
-
(3)用于模式匹配字符串的方法
-
- search()
-
replace()
-
match()
-
split()
-
四、new RegExp()
-
- RegExp对象的属性
-
RegExp对象的方法
-
五、实战应用
-
- (1)判断电话号码格式
-
(2)判断邮箱格式
-
(3)判断昵称格式
-
结束语
===========================================================
其实我写这篇文章的话,主要是想自己重新复习一遍正则表达式。我们也知道正则表达式在很多语言中都是通用的,所以学好这个好处很多。接下来,就跟我一起来学习一下正则表达式,从0到入门吧。
- 公众号:前端印象
- 不定时有送书活动,记得关注~
- 关注后回复对应文字领取:【面试题】、【前端必看电子书】、【数据结构与算法完整代码】、【前端技术交流群】
===========================================================
正则表达式(regular expression)是一个描述字符模式的对象,简单点来讲就是通过正则表达式规定的模式,从一堆字符串中,找到与该模式匹配的字符串,并可以完成检索或字符串替换的功能。
来举个例子,让大家更形象地理解正则表达式的作用。
你去买苹果,老板给你随便拿了几个,但你觉得他给你挑的苹果不好,于是你想从中拿掉一些不好的苹果,再去挑一些好的苹果,在选之前,你先想好自己挑选苹果的标准,比如苹果的纹路要多 、苹果要很红 、苹果不能太大等等,然后再根据你自己定的标准去这么多苹果里挑选到完全符合你标准的苹果放进自己的袋子里,或者是替换掉袋子里你觉得不好的苹果。
希望你们能对正则表达式有个初步的印象。
在JavaScript中,正则表达式用RegExp对象表示,我们可以通过两种方式创建一个正则表达式对象:
-
RegExp直接量
-
new RegExp()
let pattern = /javascript/
这样双正斜杠包裹一个匹配模式的写法就是RegExp直接量,这种方法其实是new RegExp()的一种能语法糖的写法。这一部分我们都用RegExp直接量的方法来讲解,在后面我们会介绍 new RegExp() 的用法
(1)正则表达式初体验
接下来看一个例子,来初次体验一下正则表达式的使用
//RegExp直接量 创建一个字符串的匹配标准
let pattern = /javascript/
let str = “I love javascript”
str.search(pattern) //返回 7
我来讲一下这段代码,首先我们通过两个正斜杠//
创建了一个正则表达式对象,然后将我们要匹配的字符串放到这两个斜杠中,我们例子中就是将javascript放到两个斜杠中,意思就是我们的匹配标准就是:要匹配到javascript这段字符串。然后我们调用了一个检索的方法search(),这个方法需要传入一个正则表达式对象为参数,根据这个参数去字符串中匹配相应的字符串,如果匹配到了,则返回第一个与之匹配的字符的索引值;若没匹配到,返回-1。例子中,变量str中有一段字符串为javascript,所以匹配成功,并返回javascript的开头字母的索引值,为7
(2)深入了解正则
刚才我们体验了一下最简单的正则表达式去匹配字符串。在上一个例子中,我们将javascript作为标准去匹配,其实大多数的字符都是按照字面含义去匹配的,意思就是你输入什么字符,就去匹配什么字符,比如/python/
就是去字符串中匹配 python
字符串 、/123/
就是去匹配 123
字符串
但是在正则表达式中,\
反斜杠有特殊的作用,在一些字符前面加一个反斜杠,能起到转义的作用。例如 /n/
是匹配字符串 n
的,但是/\n/
中,n的前面加了一个反斜杠,就将其转义了,这个匹配模式的意思就是去匹配换行符,下面列出一些其他的转义字符
| 字符 | 匹配 |
| — | — |
| 字母和数字字符 | 自身 |
| \o | NUL 字符(\u0000) |
| \t | 制表符(\u0009) |
| \n | 换行符(\u000A) |
| \v | 垂直制表符(\u000B) |
| \f | 换页符(\u000C) |
| \r | 回车符(\u000D) |
在正则表达式中,许多标点符号都具有特殊的含义,它们是:^ $ . * + ? = ! : | \ / ( ) [ ] { }
,当我们想要匹配这些字符时,也需要在它们前面加上反斜杠 \
,例如
/--------------不对小括号进行转义----------------/
let pattern = /you(kimy)/
let str = “I love you(kimy)”
str.search(pattern) //返回 -1 表示未匹配到相应字符
/--------------对小括号进行转义-----------------/
let pattern = /you(kimy)/
let str = “I love you(kimy)”
str.search(pattern) //返回 7 表示匹配成功
为什么这些标点字符需要进行特殊的转义呢?因为它们有别的用处,我们接下来会慢慢介绍他们的用处
字符类
将直接量字符单独放在方括号里就组成了一个字符类,一个字符类可以匹配它所包含的任意字符。例如/[abcd]/
就是匹配到 a
、b
、c
、d
四个字符中的任意一个即为匹配成功。如果在方括号里最前面加上一个 ^
符号,则表示为,只要匹配到一个不是方括号里的字符的字符串即为匹配成功,例如 /[^abc]/
就是匹配到不是 a
、b
、c
三个字符中的任意一个即为匹配成功。 字符类还可以使用 -
来表示字符的一个范围,例如 /[a-zA-Z0-9]/
表示匹配到任意一个大小写字母或者数字都为匹配成功。
在正则表达式中,还给出了一些特殊字符的转义,我们来看下列的表格
| 字符 | 匹配 |
| — | — |
| […] | 方括号内的任意一个字符 |
| [^…] | 不在方括号内的任意一个字符 |
| . | 除了换行符和其他Unicode行终止符之外的任意字符 |
| \w | 相当于[a-zA-Z0-9] |
| \W | 相当于[^a-zA-Z0-9] |
| \s | 任何Unicode空白符 |
| \S | 任何非Unicode空白符 |
| \d | 任何数字,相当于[0-9] |
| \D | 任何非数字,相当于[^0-9] |
| [\b] | 退格直接量 |
我们来选取表格中的 \d
来举个例子
let pattern = /python\d/
let str = “I love python3”
str.search(pattern) //返回 7
我们设置的匹配模式是 /python\d/
,表示匹配到一个字符串为python并且后面紧跟一个任意数字即可,所以成功匹配到 str 中的python3
字符串
重复
在上一部分,我们知道字符类都是匹配一个字符,例如 /\d/
和 /[0-9]/
都是匹配任意一个数字 、/[abcd]/
也是匹配一个字符,那如果我们想要匹配多个字符串岂不是要写很多遍重复代码?例如我们要匹配一个三位数字的字符串,我们就需要设置这样一个匹配模式 /\d\d\d/
。 其实正则表达式有几种语法,可以将该表达方式简化,我们来看一下这个表格
| 字符 | 匹配 |
| — | — |
| {n,m} | 匹配前一项n-m次 |
| {n,} | 匹配前一项至少n次 |
| {n} | 匹配前一项n次 |
| ? | 匹配前一项0次或1次,相当于{0,1} |
| + | 匹配前一项至少一次,相当于{1,} |
| * | 匹配前一项0次或更多次,相当于{0,} |
我们接下来就利用这些语法进行一下重复操作,例如我们要匹配一段字符串中的11位数字,我们可以这样写 /\d{11}/
,因为\d
表示的是任意数字,在它后面加上一个重复语法,就是重复\d
多少次。我们如果要匹配一个三位的字母并且后面跟上一个一位的可选数字,我们可以这样 /[a-zA-Z]{3}\d?/
,[a-zA-Z]{3}
表示匹配任意三位字母,\d?
表示匹配数字0次或1次
重复是贪婪的,它们会尽可能的多地匹配,我们称之为贪婪的重复,下面来看一个例子
let pattern = /\d{3,10}/
let str = “0123456789”
str.match(pattern)[0] //返回 0123456789
这里介绍一个新的匹配方法 match
,它可以将匹配到的一段字符串放在一个数组里,若没匹配到则返回null。 在这个例子中,我们设置的匹配模式是/\d{3,10}/
,表示匹配数字3到10次,因为重复语法默认是贪婪的,它会尽可能多地匹配,所以他就匹配了任意数字10次,返回 0123456789
。
那么如果我们如何使他们不贪婪地重复呢?其实很简单,我们只需要在重复的语法后面加一个 ?
即可将重复变成非贪婪的,还是这个例子
let pattern = /\d{3,10}?/
let str = “0123456789”
str.match(pattern)[0] //返回 012
这是我们可以看到,在重复语法 {3,10}
后面加上一个 ?
以后,它并没有尽可能多地匹配了,而是变成了尽可能少地匹配,即匹配三次任意数字就结束匹配。
还有其他的非贪婪重复的语法有: ??
、+?
、*?
,你们可以下去自行测试
选择
在JavaScript中有一个运算符可以用在正则表达式中,那就是 |
,它的意思就是或者,例如这个例子 /[a-z]|[0-9]/
意思就是可以匹配任意一个a-z的字母,或者也可以匹配任意一个0-9的数字。
在复杂的例子里,我们也可以这样使用,先给出需求,匹配一段字符串,它可以是3位的不区分大小写的字母,也可以是4位的数字
let pattern = /[a-zA-Z]{3}|\d{4}/
let str = “Lpyexplore2333”
str.match(pattern)[0] //返回 Lpy
在这个例子中,我们匹配的模式是3位的不区分大小写的字母或者4位数字,但是 str 中既有3位的不区分大小写的字母,也有4位数字,为什么最后只是返回了Lpy呢? 因为正则的匹配是从字符串的最左边开始匹配,只要有一个符合匹配模式的就停止匹配。
分组与引用
上面我们说过,在正则表达式中小括号是有特殊含义的,如果真的想要匹配带有小括号的字符串,必须要用反斜杠转移,接下来我们就来介绍一下 ()
小括号的几种作用。
- 作用一: 把匹配模式中的部分项组合成子表达式
类似于这样 /java(script)?/
,这种匹配模式的意思就是,匹配一段为 java
或者 javascript
的字符串。我们可以试一下,如果去掉这个括号会是什么结果,即 /javascript?/
,这种匹配模式的意思就是,匹配一段为 javascrip
或者 javascript
的字符串。
所以我们可以很清楚的知道,()
小括号可以帮我们组合一个子表达式,然后将这个子表达式作为整体,配合 |
、*
、?
、+
等符号去处理。
- 作用二:定义一个子匹配模式,方便获取子匹配模式匹配到的字符串
在将这个作用前,我还是再来详细介绍一下我之前例子中用到的匹配方法 match()
的具体用法。
match() 方法需要传入一个正则表达式,然后根据这个参数去匹配字符串,最后返回一个数组,数组的第一个元素是该参数匹配到的字符串,数组的第二个元素是该正则表达式中第一个()
小括号内匹配到的字符串,数组的第三个元素是该正则表达式中第二个()
小括号内匹配到的字符串,这样以此类推。若没匹配到就返回null
介绍完 match() 方法的使用以后,我们来看一个例子
/---------------------在匹配模式中加小括号--------------/
let pattern = /java(script\d+)/
let str = “javascript2333”
str.match(pattern) //返回 [‘javascript2333’, ‘script2333’]
/---------------------不在匹配模式中加小括号--------------/
let pattern = /javascript\d+/
let str = “javascript2333”
str.match(pattern) //返回 [‘javascript2333’]
我们可以看到,在匹配模式中加了小括号,最后返回的数组中会额外返回一个元素,用于存放小括号定义的子匹配模式匹配到的字符串。
接下来举一个实战中的例子
有这样一个 url 地址 https://www.baidu.com/s?query=javascript
,我们知道 ?
后面跟的是请求参数,如果我们想要获取请求参数 query 的值,也就是 query=
后面的字符串,我们该如何使用正则表达式去匹配呢?
let pattern = /query=([a-zA-Z]+)/
let str = “https://www.baidu.com/s?query=javascript”
str.match(pattern) //返回 [‘query=javascript’, ‘javascript’]
在这个例子中,我们很明确的知道我们只是想获取 query=
后面的字符串,但是如果我们直接用这个模式 /query=[a-zA-Z]+/
去匹配的话,我们最后只能获得 query=javascript
这样一整段字符串。所以我们可以在我们可以使用小括号来定义一个子匹配模式,这样在返回的数组中直接获取小括号匹配返回的值就可以了。
- 作用三:小括号定义的子匹配模式可以被反斜杠+数字再次引用
其实作用三是在作用二的基础上的,我们可以通过一个反斜杠 \
加上数字 n来引用该匹配模式中第n个括号定义的子匹配模式,例如 /java(script)\1/
,这个意思就是 \1
的部分需要匹配的字符串要跟(script)
一样
let pattern = /java(\d+)\1/
let str = “java123123”
str.match(pattern) //返回 [‘java123123’, ‘123’]
在这个例子中,\1
对(\d+)
进行了一次引用,注意是引用,而不是这样 /java(\d+)(\d+)/
。我们来看一下这两者的区别
/----------------使用反斜杠加数字引用----------------/
let pattern = /java(\d+)\1/
let str = “java123321”
str.match(pattern) //返回 null
/----------------完全的重复一遍子匹配模式----------------/
let pattern = /java(\d+)(\d+)/
let str = “java123321”
str.match(pattern) //返回 [‘java123321’, ‘12332’, ‘1’]
通过这两个例子的对比,我们可以发现以下几点区别:
-
子匹配模式
必须和反斜杠+数字
匹配到的字符串一模一样,否则匹配失败 -
两个相同的子匹配模式则不需要两者匹配到一模一样的字符串
-
反斜杠+数字
虽然是对定义的子匹配模式的引用,但在匹配返回的结果里,却不会返回反斜杠+数字
匹配到的内容
补充:如果我们用小括号定义的子匹配模式不想被反斜杠+数字
引用,我们可以在小括号内部的最前面加上 ?:
,即这种形式 (?:\d+)
,这样的话我们就无法在后面使用 反斜杠+数字
来引用这个子匹配模式了。
例如:
let pattern = /java(?:script)(\d+)\1/
let str = “javascript1212”
str.match(pattern) //返回 [‘javascript1212’, ‘12’]
例子中我们可以看到, \1
是对第二个子匹配模式(\d+)
进行了引用,其实我们可以这样理解,使用这种形式(?:...)
定义的子匹配模式,不会被计入编号中,所以也不会被 反斜杠+数字
引用。
指定匹配位置
在正则表达式中,我可以利用某些字符,去指定匹配发生的位置。这些字符我们称之为正则表达式的锚。
| 字符 | 含义 |
| — | — |
| ^ | 匹配字符串的开头 |
| $ | 匹配字符串的结尾 |
| \b | 匹配一个单词的边界 |
| \B | 匹配非单词边界的位置 |
| (?=p) | 零宽正向先行断言,?=后面的字符都要与p匹配,但不能包括p的那些字符 |
| (?!p) | 零宽负向先行断言,?!后面的字符不与p匹配 |
我们来逐个说一下这几个字符的用法:
- ^ 符号
^ 这个符号是将匹配位置定位到字符串的开头,直接来看一个例子
/--------------------------第一种情况--------------------/
let pattern = /^javascript/
let str = “javascript is fun”
str.match(pattern) //返回 [‘javascript’]
/--------------------------第二种情况--------------------/
let pattern = /^javascript/
let str = “i love javascript”
str.match(pattern) //返回 null
我们匹配的模式是,要以javascript开头的字符串。第一种情况,字符串以 javascript
开头,所以能匹配到;第二种情况,javascript
不是在开头的位置,而是在末尾的位置,不符合匹配模式,所以匹配失败返回null。
在前面我们有一个地方还用到了 ^ 这个符号,那就是 [^abc]
,所以一定要注意,当 ^ 放在方括号里,表示的是取反,也就是说不匹配方括号里的任何字符。
- $ 符号
$ 这个符号是将匹配位置定位到字符串的末尾,直接来看一个例子
/--------------------------第一种情况--------------------/
let pattern = /javascript$/
let str = “javascript is fun”
str.match(pattern) //返回 null
/--------------------------第二种情况--------------------/
let pattern = /javascript$/
let str = “i love javascript”
str.match(pattern) //返回 [‘javascript’]
我们的匹配模式是,字符串要以javascript结尾。第一种情况,字符串结尾处字符是 fun ,不符合匹配模式,返回null;第二种情况,结尾处字符为javascript,符合匹配模式,所以匹配成功。
我们可以看一下如果 ^ 符号 和 $ 符号一起使用是什么情况:
let pattern = /^javascript$/
let str = “javascript”
str.match(pattern) //返回 [“javascript”]
当这两个符号一起使用时,匹配模式就变成了匹配整段字符串,并且字符串的内容就是 ^ 与 $ 之间的内容
- \b
这个符号的作用是匹配一个单词的边界,我们来看几个例子来理解一下
/-------------------------第一种情况----------------------/
let pattern = /\bjava/
let str = “I love javascript”
str.match(pattern) // 返回 [‘java’] 匹配成功
/-------------------------第二种情况----------------------/
let pattern = /\bjava/
let str = “javascript is fun”
str.match(pattern) // 返回 [‘java’] 匹配成功
/-------------------------第三种情况----------------------/
let pattern = /\bjava/
let str = “1javascript is fun”
str.match(pattern) // 返回 null 匹配失败
/-------------------------第四种情况----------------------/
let pattern = /java\b/
let str = “I am learning java”
str.match(pattern) // 返回 [‘java’] 匹配成功
/-------------------------第五种情况----------------------/
let pattern = /java\b/
let str = “I am learning javascript”
str.match(pattern) // 返回 null 匹配失败
/-------------------------第六种情况----------------------/
let pattern = /\bjava\b/
let str = “I think java is fun”
str.match(pattern) // 返回 [‘java’] 匹配成功
看了上面几个例子,你有没有得出什么规律?
其实 \b
的作用就是将匹配的点放到一个字符串前面(\b放前面)或后面(\b放后面)的 [^a-zA-Z0-9]
处,也可以理解为 \b 可以替换那些特殊字符,但 \b 不会作为匹配的内容。
- \B
\B 则与 \b 相反了, \b 可以替换那些特殊字符,那么\B就是用来替换那些非特殊字符,也就是 [a-zA-Z0-9]
内的字符。
也来举几个简单的例子吧
/-------------------------第一种情况----------------------/
let pattern = /java\B/
let str = “I love javascript”
str.match(pattern) // 返回 [‘java’] 匹配成功
/-------------------------第二种情况----------------------/
let pattern = /java\B/
let str = “I love java”
str.match(pattern) // 返回 null 匹配失败
/-------------------------第三种情况----------------------/
let pattern = /\Bjava\B/
let str = “I love 1javascript”
str.match(pattern) // 返回 [‘java’] 匹配成功
/-------------------------第四种情况----------------------/
let pattern = /\Bjava\B/
let str = “I love javascript”
str.match(pattern) // 返回 null 匹配失败
- (?=p)
(?=p)表示接下来的字符要与p匹配,但p不会作为内容返回
先来看一个例子
let pattern = /java(script)?(?=:)/
let str = “java: my favorite language”
str.match(pattern) //返回 [“java”, undefined] 匹配成功
该例子的匹配模式:匹配一段字符串为java 然后 script 可以有一个也可以没有,后面必须跟一个 :
,才能匹配成功,返回匹配内容,但是匹配内容中不包含 :
再来看一个类似的例子
let pattern = /java(script)?(?=:)/
let str = “javascript is my favorite language”
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip1024c (备注前端)
最后
四轮技术面+一轮hr面结束,学习到了不少,面试也是一个学习检测自己的过程,面试前大概复习了 一周的时间,把以前的代码看了一下,字节跳动比较注重算法,面试前刷了下leetcode和剑指offer, 也刷了些在牛客网上的面经。大概就说这些了,写代码去了~
祝大家都能收获大厂offer~
篇幅有限,仅展示部分内容
何学起的朋友,同时减轻大家的负担。**
[外链图片转存中…(img-ktOA0Nsp-1711952142719)]
[外链图片转存中…(img-Y5F1qh3j-1711952142720)]
[外链图片转存中…(img-YNhcRjRG-1711952142720)]
[外链图片转存中…(img-Ocy8ceVs-1711952142721)]
[外链图片转存中…(img-SghHpmQ0-1711952142721)]
[外链图片转存中…(img-J1knpQ7V-1711952142721)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip1024c (备注前端)
[外链图片转存中…(img-EzXtkunw-1711952142722)]
最后
四轮技术面+一轮hr面结束,学习到了不少,面试也是一个学习检测自己的过程,面试前大概复习了 一周的时间,把以前的代码看了一下,字节跳动比较注重算法,面试前刷了下leetcode和剑指offer, 也刷了些在牛客网上的面经。大概就说这些了,写代码去了~
祝大家都能收获大厂offer~
篇幅有限,仅展示部分内容