JS中的第二世界--正则表达式
近期的繁忙让我一直没有空闲静下心来好好写一些文章。好在,所有的忙碌都已过去,愿明天更美好。刚过完七夕,带着欢乐的心情写下这篇文章。希望读者能够喜欢哟~~
你是不是经常遇到正则,却不知它在说什么,你是不是就算再项目中看到了,也会选择一眼略过,你是不是整天忘记搜索什么,却不知道有的编辑器搜索支持正则的模糊搜索……
熟悉的旋律萦绕在耳边,却早已不是当初的少年。
工作了很久之后,猛然发现之前自己忽略的正则是这么重要。搜索、查询、命令行、校验、截取、替换…………哪样哪样都离不开这个小东西。很多人不知道的是,正则在 JavaScript
里仿佛一个第二世界一样。看起来简单,实则有很多让我们摸不着头脑的操作。
接下来,让我们顺着本文的介绍,一点儿一点儿深入了解正则表达式,知晓正则的强大能力!
1. 创建正则表达式
在 JavaScript
中创建正则表达式有两种方式
第一种:构造函数创建
const reg = new Reg('正则表达式')
第二种:字面量创建
const reg = /正则表达式/
2. 使用正则表达式匹配内容
正则匹配分为 精准匹配 和 模糊匹配
精准匹配
只需要我们将需要匹配的内容放入到正则表达式中匹配即可。上手简单
const reg = /正则表达式/
const str = '这是一篇写正则表达式是文章'
str.match(reg) // 正则表达式
这里的正则表达式会精准的搜索到我们要搜索的内容。
模糊匹配
模糊匹配需要用到第三点所描述的内容,这里我们先看下
const reg = /[\u4e00-\u9fa5]+/
const str = '这是一篇写正则表达式Regpx的内容'
str.match(reg) // 这是一篇写正则表达式
这里的正则表达式会根据我们传入的规则来匹配要搜索的内容。注意:这里的\u4e00-\u9fa5
表示的是中文范围
\u4e00
表示的是字符集中第一个中文汉字
\u9fa5
表示的是字符集中最后一个中文汉字
ok,知道了怎么创建和使用正则,接下来我们来真正了解一下他吧。
3. 正则表达式介绍
通晓元字符的同学可跳过此小节,直奔第四小节查看。主要内容有 . | \ * + ? () [] {} ^ $
几种字符使用方法,含义和注意事项,内置匹配项,贪婪和惰性匹配。
首先介绍一下前瞻条件,正则可以根据自己的设置来进行多行和全局,局部,忽略大小写等匹配模式,分为:
m
:多行匹配g
: 全局匹配i
: 忽略大小写
接下来的内容,就可以看到我们来使用它
3.1 元字符
元字符是正则表达式中最基础的部分,它代表了我们可以查询的内容。come on baby。让我们来认识一下他们吧。
- 点
.
:匹配除去\n
之外的所有内容
const reg = /.*/
const str1 = 'abc'
// 在str2中添加 \n 换行符
const str2 = 'a\nb\nc'
str1.match(reg) // abc
str2.match(reg) // a
- 或
|
:在正则中进行逻辑判断,(说的比较抽象,我们来看下例子)
const reg = /正则|表达/
const str1 = '正则表达式'
const str2 = '表达式'
str1.match(reg) // 正则
str2.match(reg) // 表达
解释:
如果可以匹配到 |
前边的内容,则匹配前边的。
匹配不到前边的,但是可以匹配后边的内容,则匹配后边的
- 反斜杠
\
:表示转义
const reg = /\./
const str = 'a.b.c.d'
str.match(reg) // .
可以匹配除 \n
外任意字符的点 .
在使用 \
转义之后只能匹配到 .
这个字符
需要注意的点:
在有的编程语言中,匹配 \\
需要四个反斜杠 -- \\\\
。但是在 javascript
中,只需要两个。
const reg = /\\/
const str = '\\'
str.match(reg) // \\
- 星号
*
:需要匹配的内容出现连续零次或多次
const reg = /a*/
const str1 = 'aaabbcccddd'
const str2 = 'bbcccddd'
reg.test(str1) // true
reg.test(str2) // true
- 加号
+
:需要匹配的内容出现连续一次或多次
const reg = /a+/
const str1 = 'aaabbcccddd'
const str2 = 'bbcccddd'
reg.test(str1) // true
reg.test(str2) // false
- 问号
?
:需要匹配的内容出现连续零次或一次
const reg = /a?/
const str1 = 'aaabbcccddd'
const str2 = 'bbcccddd'
reg.test(str1) // true
reg.test(str2) // true
- 小括号
()
: 表示组,小括号中的内容表示一组,整体进行匹配。
const reg = /(abc)/
const str1 = 'abab'
const str2 = 'abcab'
reg.test(str1) // false
reg.test(str2) // true
拓展:
使用小括号包裹的匹配内容,可在后续的正则中通过\ + 序号
的方式继续调用。有几个小括号就有几个序号。序号从1开始
const reg = /(abc)\1/ // 相当于 const reg = '(abc)abc'
const str = 'abcabc'
str.match(reg)
// /(a)(b)(c)\1\2/ ---> /(a)(b)(c)ab/
- 中括号
[]
:表示范围,括号中的内容只要有一个匹配到就可以
const reg = /[abc]/
const str = "efg"
const str1 = 'aef'
reg.test(str) // false
reg.test(str1) // true
注意:
中括号中可以使用 -
来表示连续的范围
/[0-9]/ 0123456789
/[a-z]/ 全部英文小写
/[A-Z]/ 全部英文大写
- 大括号
{m,n}
:表示出现次数
m
表示最少出现多少次 n
表示最多出现多少次,n
可省略,表示无限次
const reg = /a{1,4}/ // a最少出现1次,最多出现4次
const str = 'aaaaa'
reg.test(str) // true
拓展:
{0,}
相当于 *
{1,}
相当于 +
{0,1}
相当于 ?
- 开头
^
:只匹配开头内容
const reg = /a^/
const str = 'abc'
const str1 = 'bac'
reg.test(str) // true
reg.test(str1) // false
注意:
此符号用在 []
中,表示取反操作
const reg = /[^abc]/g
const str = '123'
str.match(reg) // ['1', '2', '3']
这里只能取到不是 abc
的内容
- 结尾
$
: 只匹配结尾
const reg = /a$/
const str = 'abc'
const str1 = 'cba'
reg.test(str) // false
reg.test(str1) // true
3.2 内置匹配符
\d
:数字
\D
:非数字
\s
:空格
\S
:非空格
\w
:数字字母下划线
\W
:非数字字母下划线
\b
:字符边界
\B
:非字符边界
const str = 'hello word! 520'
console.log(str.replace(/\d/g, '*')) // hello word! ***
console.log(str.replace(/\D/g, '*')) // ************520
console.log(str.replace(/\w/g, '*')) // ***** ****! ***
console.log(str.replace(/\W/g, '*')) // hello*word**520
console.log(str.replace(/\b/g, '*')) // *hello* *word*! *520*
console.log(str.replace(/\B/g, '*')) // h*e*l*l*o w*o*r*d!* 5*2*0
console.log(str.replace(/\s/g, '*')) // hello*word!*520
console.log(str.replace(/\S/g, '*')) // ***** ***** ***
3.3 贪婪和惰性
贪婪匹配是最多情况下匹配内容
惰性匹配是最少情况下匹配内容
先看栗子
const reg = /a[bc]*c/g // 贪婪
const str = 'abcbcbc'
console.log(str.match(reg)) // [ 'abcbcbc' ]
const reg1 = /a[bc]*?c/g // 惰性
console.log(str.match(reg1)) // [ 'abc' ]
解释:
- 贪婪: 由于
abcbcbc
一直到字符串最后都符合正则的规则,所以一直匹配到不符合位置 - 惰性:只匹配一个符合规则的就返回,不继续匹配。
4. 正则进阶操作
4.1 具名组匹配
JavaScript
中提供了组匹配的能力。可以同过自定义的组名来获取匹配内容.
组的固定格式为 ?<组名>
。然后通过获取结果的groups.具体的名称
来获取
const reg = /(?<name>[a-zA-Z]{3,6})(?<age>\d{2})/
const str = 'xiaoming23'
str.match(reg).groups.name // xiaoming
str.match(reg).groups.age // 23
4.2 位置匹配
?=搜索内容
:查看右侧内容是否符合条件, 查看后缀是否为要搜索的内容。
const reg = /(?=abc)/
const str = 'efabcefabc'
str.replace(reg, '*') // ef*abcef*abc
解释:
匹配 后缀为abc
这个字符的位置
?!搜索内容
:查看右侧内容是否不符合条件,查看后缀是否为要搜索的内容
const reg = /(?!abc)/
const str = 'efabcefabc'
str.replace(reg, '*') // *e*fa*b*c*e*fa*b*c*
解释:
匹配 后缀不为 abc
这个字符的位置
?<=搜索内容
:查看左侧内容是否符合条件,查看前缀是否是要搜索的内容
const reg = /(?<=abc)/
const str = 'efabcefabc'
str.replace(reg, '*') // efabc*efabc*
解释:
匹配 前缀为abc
这个字符的位置。
?<!搜索内容
:查看左侧内容是否不符合条件
const reg = /(?<!abc)/
const str = 'efabcefabc'
str.replace(reg, '*') // *e*f*a*b*ce*f*a*b*c
解释:
匹配 前缀不为abc
这个字符的位置。
第四小节总结:
- 组匹配
?<组名>
- 匹配后缀
?=
和?!
- 匹配前缀
?<=
和?<!
5. 正则和字符串方法介绍
5.1 字符串方法
下述方法都支持正则匹配方式来操作。
-
replace(reg, 替换的内容 或者 一个操作函数) 替换
此方法的第二个参数是比较神奇的,可以接收要替换的内容,也可以接受一个函数。
- 为替换内容(1)
const str = 'abc' str.replace(/a/, '*') // *bc
-
为替换内容(2)
可使用
$1,$2…………
等变量作为匹配到的组的内容。
const str = '123abc' str.replace(/(a)(b)(c)/, '$1$3$2') // 123acb
说明:
$1
代表(a)
所匹配到的内容$2
代表(b)
所匹配到的内容$3
代表(c)
所匹配到的内容替换的时候掉到顺序替换,则输出
123acb
这个值- 为函数
const str = 'abc' str.replace(/(a)/, (source, $1, index) => { console.log(source, $1, index) // abc a 0 return * }) // *ab str.replace(/(b)(c)/, (source, $1, $2, index) => { console.log(source, $1, $2, index) // abc return $1 + 1 }) // a11
说明:
函数参数接收的参数,第一个
source
为字符串本身,最后一个index
为查找到的第一个索引值。中间的$1, $2, $3………………
为正则表达式里小括号的数量。返回值的作用是作为替换内容替换原字符串。 -
match 搜索
根据正则的规则匹配字符串
const reg = /[abc]/g const str = 'abc' str.match(reg) // [ 'a', 'b', 'c' ]
-
split 切割
const str = 'abcabcabc' str.split(/ca/) //[ 'ab', 'b', 'bc' ]
此方法还可接收第二个参数。
length
设置返回的数组长度const str = 'abcabcabc' str.split(/ca/, 2) //[ 'ab', 'b' ]
5.2 正则方法
-
test 查看字符串是否符合正则规则
const reg = /abc/ const str = 'abc' const str1 = 'ab' reg.test(str) // true reg.test(str1) // false
-
exec 根据正则的规则匹配字符串。同
match
const reg = /abc/ const str = 'abc' const str1 = 'ab' reg.exec(str) // 'abc' reg.exec(str1) // null
6. 实战篇
理解了内容之后怎么也得练练手啊,此内容给大家准备了几个常见但是不太好理解的正则,请大家练手。
6.1 匹配 html 标签 (包含标签中的内容)
首先,我们来创建个字符串
const html = '<div></div>'
现在我们来抒写一下可描述标签的正则表达式。有以下几个特征:
- 以
<
开头 - 标签名为英文字符
- 以
</标签名>
结尾
第一版表达式
const reg = /<(\w+)><\/(\1)>/g
// 验证一下
html.match(reg) // '<div></div>'
\1
引用上一个分组的正则规则上面的内容已经说过。
看我们的验证结果,完美。但是,有个问题。我们的标签一般都不在一行内书写,标签之间会有 \n
来标识换行。ok,让我们修改一下 html
字符串
const html = `<div>
</div>`
// 再次验证
html.match(reg) // null
😰完了,失败了。
不要着急,我们只匹配了标签,并没有匹配到标签中的内容。由于 .
并不能匹配到 \n
所以我们使用其他条件来匹配。
第二版表达式
const reg = /<(\w+)>([\s\S]*)<\/(\1)>/g
// 验证
html.match(reg) // '<div>\n\n</div>'
(o)/,成功。
这里我们可以看到。使用 [\s\S]
可以匹配到 \n
。因为 [\s\S]
代表的是空格和非空格。相同的用法还有 [\w\W]、[\b\B]、[\d\D]
第三版表达式
html
除了双标签还有单标签,下面我们来看下单标签的验证。单标签的开始跟双标签一样。但是结束不一样,单标签是以/>
结束。不说了,先写一下
let reg = /<(\w+)/ // 相同的开头
// 结束规则书写
reg = /<(\w+)\/>/
注意,这里,单标签中的内容,我们不需要用 [\s\S]
这种方法验证,会有其他问题,因为我们需要匹配的是属性,匹配到换行符结束。所以下面这种写法就可以。
reg = /<(\w+)([^>]*)\/>/
[^>]
表示只要不是结束符号的,都符合条件。*
表示出现零次或多次
不说了,我们来验证下
const html = '<img src="" />'
html.match(reg) // <img src="" />
😄,成功。
结合版(不是终极版)
结合版的正则表达式我们需要用到元字符中的|
来作为分支判断
const reg = /<(\w+)>(([\s\S]*)<\/(\1)>)|(([^>]*)\/>)/mg
// (([\s\S]*)<\/(\1)>) 双标签
// (([^>]*)\/>)单标签
说明:m
的作用是来表示匹配多行。g
的意思是表示全局匹配
验证一下
const html = '<div title="1"></div><p></p><img src="asfs" alt="asdfa"/><br />'
html.match(reg)
// [ '<p></p>', '<img src="asfs" alt="asdfa"/>', '<br />' ]
成功!!
虽然这次的匹配成功了,但是这个表达式还是有很多问题,期待读者来完善哟。
6.2 实现数字千分位
同样,我们来分析一下需求。千分位是每隔三个数字,加上一个逗号。首先,我们先创建一个数字的字符串
const str = '12345678'
查看后缀是否是三个数字,我们使用 ?=
来做,它的作用就是查看后缀是否符合规则。先来创建正则
第一版
const reg = /(?=\d{3})/g
因为需要匹配整个数字,所以我们用到了 g
来表示全局匹配。好,正则创建完成,验证一下。
str.replace(reg, ',') // ,1,2,3,4,5,678
整个结果,好像有问题啊。
不着急,继续向下看,由于我们要数字三个一对的出现,所以这里我们需要添加出现一次或多次的校验。使用+
第二版
const reg = /(?=(\d{3})+)/g
先不急着验证,因为还没有完成。由于每三个字符是一个节点,所以这里还需要用 $
来表示查找结束。
第二版改进
const reg = /(?=(\d{3})+$)/g
验证:
str.replace(reg, ',') // 12,345,678
貌似是成功了,多来验证几次。
…………
验证到这个字符串时出现问题。
const str = '123456789'
str.replace(reg, ',') // ,123,456,789
这里我们看到,数字正好是九位,所以开始的 123
也符合条件。所以需要吧开头禁止掉。使用 ?!
这种方式
第三版
const reg = /(?!^)(?=(\d{3})+$)/g
再次验证:
str.replace(reg, ',') // 123,456,789
7. 总结
好了,本次的内容我们就先分享到这里了,期望你能从这篇文章中真正了解到正则表达式。本篇文章一共分享了一下几个内容
- 元字符
- 位置匹配
- 字符串和正则表达式方法讲解
- 实战操作
正则的使用方式千变万化。所谓能力越大,危害就越大,只有真正掌握了它,才能在实际应用中得心应手,否则容易造成不小的祸端。
那么,再见了,亲爱的读者朋友们,期待下次相遇~~