一文带你学习正则表达式
正则表达式,对于前端而言是不可或缺的技能。表单验证、查找字符串、字符串格式化等等一系列常规操作都需要使用到正则。
通过单个字符串来描述、匹配满足条件的规则字符串,它是繁琐的,同时也很强大,接下来一文带你了解什么是正则表达式。
语法
例如匹配一个千分位格式
let str = '12,545,545'
let reg = /^(\d{1,3},)+(\d{3})$/
console.log(reg.test(str)) // true
一般的正则表达式都是由两条/前后封闭形成,在上述正则表达式中,以^表示规则的开始,从左到右依次组
合,\d表示0-9的任意数字,{1,3}表示前面的任意数字至少有1个,至多为3个,","紧跟在后面,表面1-3个任意数字后必须跟
一个",",将"\d{1,3},"用()包起来表示一个表达式,()外的+表示()中的内容至少要有一个或多个,第二个括号里表示固定的
任意三个数字,最后由$表示规则的结束。
前端一般使用正则对象的test方法进行校验(上方例子)
前端一般使用字符串的replace方法进行格式化字符串以及使用match方法匹配满足正则的字符串:
// 格式化千分位(replace方法)
let str = `123145641221`
let newStr = str.replace(/\d{1,3}(?=(\d{3})+$)/g, (s) => `${s},`)
console.log(newStr) // '123,145,641,221'
// 查找满足条件的子字符串(match方法)
let str = 'uzi yyds dddd'
let reg = /\bd\w+/
let reg1 = /d\w+/
str.match(reg) // ['dddd', index: 9, input: 'uzi yyds dddd', groups: undefined]
str.match(reg1) // ['ds', index: 6, input: 'uzi yyds dddd', groups: undefined]
格式化千分位方法中,我们先匹配千分位的开头,因为千分位的开头数字的位数是不确定的,所以用\d{1,3}来匹配
,而大()中的?=则表示的是寻找小()中三个任意数字的前一个表达式的内容,通俗的表达就是要匹配任意1-3个数字
后必须要有3个任意数字,然后g修饰符则表示匹配整个字符串的内容。
在查找子字符串方法中,为什么我们的reg1到的是ds,而不是dddd。因为在d前面加了\b定位符,表示d前边必须
没有元素,或者为空格。若\b在d的后面,则表示d的后面必须没有元素或为空格。
修饰符
修饰符 | 含义 | 说明 |
---|---|---|
i | ignore - 不区分大小写 | 将匹配设置为不区分大小写,搜索时不区分大小写: A 和 a 没有区别。 |
g | global - 全局匹配 | 查找所有的匹配项。 |
m | multi line - 多行匹配 | 使^ 也匹配 '\n' 或 '\r' 之后的位置,$ 也匹配 '\n' 或 '\r' 之前的位置。 |
s | 特殊字符圆点 . 中包含换行符 \n | 默认情况下的圆点 . 是 匹配除换行符 \n 之外的任何字符,加上 s 修饰符之后, . 中包含换行符 \n。 |
元字符
字符类型 | 描述 |
---|---|
\ | 转义字符,使*,+,?等特殊字符失去特殊含义,仅为普通符号使用,例: \ * \+ \? |
^ | 匹配输入字符串的开始位置 |
$ | 匹配输入字符串的结束位置 |
* | 匹配前面的子表达式零次或多次 例: /10*/能匹配1与100 |
+ | 匹配前面的子表达式1次或多次 例: /10+/能匹配10与100但不能匹配1 |
? | 匹配前面的子表达式零次或1次 例: /10?/能匹配1与10 但不能匹配100,当?紧跟在 (*, +, ?, {n}, {n,}, {n,m})后时匹配模式是非贪婪的,10+本来可以匹配1000的,10+?则只能匹配10 |
{n} | 匹配前面的子表达式n次 例: /10{1}/只能匹配10 |
{n,m} | 匹配前面的子表达式n次到m次 例: /10{1,3}/能匹配10 100 1000 |
{n,} | 匹配前面的子表达式n次到无数次同+差不多,只是最小匹配次数可以不为1 |
. | 匹配除换行符(\n、\r)之外的 |
(x) | 匹配(x)中的x表达式并获取匹配到的结果,使用String.match则可以将一个x表达式的所有(x)匹配获取;例: var str = "http://www.runoob.com:80/html/html-tutorial.html" ------------------------------------ var patt1 = /(\w+):\/\/([^/:]+)(:\d*)?([^# ]*)/ --------------------------------------------------- str.match(patt1) --------------------------------------------------------------------------------------- // ['http://www.runoob.com:80/html/html-tutorial.html', 'http', 'www.runoob.com', ':80', '/html/html-tutorial.html', index: 0, input: 'http://www.runoob.com:80/html/html-tutorial.html', groups: undefined]
|
(?:x) | 匹配()中的x表达式但不获取匹配的结果。 |
y(?=x) | 正向肯定预查,可理解为匹配y后面为x的y。 例: [a-z](?=\d) 表示匹配a2、b4、f5等 |
y(?!x) | 正向否定预查,可理解为匹配y后面不是x的y。例: [a-z](?!\d) a2、b4等则不匹配,匹配as、a@、s_等 |
(?<=x)y | 反向肯定预查,可理解为匹配y前面是x的y。 例:(?<=\d)[a-z] 表示匹配2b、3a、4d等 |
(?<!x)y | 反向否定预查,可理解为匹配y前面不是x的y。 例:(?<!\d)[a-z] 不匹配2b、3a、4d,匹配sa、@a、_d等 |
x | y | x或y,x不匹配,则去匹配y |
[xyz] | 字符集合,匹配所包含的任意一个字符 |
[^xyz] | 负值字符集合,匹配未包含的任意一个字符 |
[a-z] | 字符范围,匹配小写字符'a'到'z'范围内的任意一个字符 |
\b | 匹配一个词的边界,例如单词和空格之间的位置 |
\B | 匹配一个词的非边界 |
\d | 匹配一个数字字符,等价于[0-9] |
\D | 匹配一个非数字字符,等价于[^0-9] |
\w | 匹配一个大小写字母或者数字、下划线,等价于[a-zA-z0-9_] |
\w | 匹配一个非大小写字母或者数字、下划线,等价于[^a-zA-z0-9_] |
\f | 匹配一个换页符 |
\n | 匹配一个换行符 |
\r | 匹配一个回车符 |
\s | 匹配一个空白字符,包括空格、制表符、换页符和换行符 |
\S | 匹配一个非空白字符 |
\xn | 匹配一个ASCII 对应的字符,例:\x41 则匹配A |
\num | 其中num是正整数,对应(x)的索引,例如:/(\d)sw([a-z])\1\2/ 其中的\1则表示(\d)匹配的结果 \2则表示([a-z])匹配的结果 |
\un | 其中n是一个4位的16进制数字,表示匹配Unicode对应的字符,例如:\u00A9 匹配版权符号©,[\u4e00-\u9fa5]则表示匹配汉字的集合 |
运算符优先级
正则表达式从左到右计算,遵循优先级顺序。不同优先级,从高到低计算,相同优先级从左到右计算
以下表格优先级从高到低排列
字符 | 含义 |
---|---|
\ | 转义字符 |
(), (?:), (?=), [] | 圆括号和方括号 |
^, $, \任何元字符、任何字符 | 定位点和序列(即:位置和顺序) |
| | 或操作 |
贪婪模式与非贪婪模式
// 贪婪模式
const reg = /穷哈{1,2}/
var str = '穷哈哈哈哈'
str.match(reg) // ['穷哈哈', index: 0, input: '穷哈哈哈', groups: undefined]
// 贪婪模式下reg会优先匹配多的,即会匹配{1,2}前的字符2次
// 非贪婪模式
const reg1 = /穷哈{1,2}?/
str.match(reg1) // ['穷哈', index: 0, input: '穷哈哈哈', groups: undefined]
// 非贪婪模式下reg则是优先匹配少的,即会匹配{1,2}前的字符1次
分组
(x)会存储匹配到的结果,\num元字符则能匹配到对应的结果
const reg = /([a-z]2) \1/g
var str = 's5 s2 s2 a2 a2'
str.match(reg) // ['s2 s2', 'a2 a2']
很明显([a-z]2)要匹配一个小写字母后跟一个2的字符串,那么reg中有\1,就表示要匹配两个字母跟一个2的字符串
即:s2 s2或者 a2 a2
使用reaplace获取(x)匹配到的结果
const reg = /([a-z]1) ([a-z]2)/
var str = 's1 a2'
str.replace(reg,'$2 $1') // 'a2 s1'
可以看到$1表示的是第一个(x)匹配的结果,$2是第二个(x)匹配的结果
使用方式
使用方式分为两类:字符串方法、正则对象下的方法
常用的方法在本文中有对应的例子,以下仅总结正则的使用方式
字符串方法(String)
match、matchAll、search、replace、split
正则对象方法(RegExp)
test、exec
动态创建正则表达式
使用RegExp构造函数,第一个参数是正则表达式,第二个参数是修饰符
const reglist = ['\\w+','\\d+','[a-z]+']
let str = '2022'
reglist.forEach(reg=>{
if (new RegExp(reg,'g').test(str)) {
console.log('hello'+str)
}
})
// hello 2022
// hello 2022
// undefined