文章目录
- 说明
- 创建正则表达式的三种方式
- 方式一
- 方式二
- 方式三
- 正则表达式修饰符
- i (IgnoreCase)
- g (global)
- m (multiple lines)
- 正则表达式
- [ ]
- ()
- 元字符
- .
- w 是word的缩写
- d 是digit的缩写
- s 是 space的缩写
- 其它间隙元字符
- 不占位修饰符
- b是border的缩写
- ^
- $
- `?=`和`?!`
- 量词
- 正则的反向引用 `(n)\数字`
- RegExp 对象方法
- `exec()` 是 execute的缩写
- `test()`
- 支持正则表达式的 String 对象的方法
- `search()`
- `match()`
- `split()`
- `replace()`
说明
后面的介绍中,我会说某些规则占位或者不占位,占位就是指匹配的结果中,有字符和这符号所表示的规则有直接联系,不占位就是所匹配的结果中没有字符和这符合有直接联系。
^
在开头属于不占位符,开始符
var reg1 = /^ab/
const result = 'abABCDab'.match(reg)
console.log(result) // ['ab'] 匹配的结果ab和^没有直接联系,规则/^ab/中,a和b是两位,所以匹配的一个字符串也只有两位
创建正则表达式的三种方式
方式一
var reg1 = /ab/
方式二
var reg2 = new RegExp(reg1)
方式三
var reg3 = RegExp(reg1)
有什么区别呢
var reg1 = /ab/
var reg2 = new RegExp(reg1)
var reg3 = RegExp(reg1)
console.log(reg1 === reg3) // true
console.log(reg1 === reg2) // false
如上代码所述,reg1和reg3本质上是同一个正则对象,相当于将reg1赋值给了reg3,但reg2不同,它深度拷贝了reg1。
再验证一下
var reg1 = /ab/
var reg2 = new RegExp(reg1)
var reg3 = RegExp(reg1)
reg1.name = 'dx'
console.log(reg2.name) // undefined
console.log(reg3.name) // dx
正则表达式修饰符
修饰符一共就只有三个 g/i/m
,它们通常出现在正则表达式的最后面,可以自由组合,顺序无所谓,但每个修饰符只能出现一次。
/ab/g
/ab/ig
/ab/gm
/ab/igm
/ab/gim
修饰符 | 描述 |
---|---|
i | 执行对大小写不敏感的匹配。 |
g | 执行全局匹配(查找所有匹配而非在找到第一个匹配后停止) |
m | 执行多行匹配 |
i (IgnoreCase)
忽略字母大小写
const reg = new RegExp(/ab/i)
const result = 'djwiAB'.match(reg)
console.log(result)
const result2 = 'fsadfaB'.match(reg)
const boolean1 = reg.test('fsadfaB')
console.log(result2)
console.log(boolean1)
result
的结果 ['AB', index: 4, input: 'djwiAB', groups: undefined]
这是一个类数组,第0位匹配到AB
result2
的结果 ['aB', index: 5, input: 'fsadfaB', groups: undefined]
类数组第0位匹配aB
boolean1
的结果是true
以上三个结果都表明,i作为忽略大小写的修饰符,挺好使,而且也经常用。
g (global)
全局匹配修饰符
const reg = new RegExp(/ab/g)
const result = 'abABCDab'.match(reg)
console.log(result) // ['ab', 'ab']
const result2 = 'abaabb'.match(/ab/)
console.log(result2) // ['ab', index: 0, input: 'abaabb', groups: undefined]
result
匹配到了两次,而result2只匹配到了一次。g
的作用就是找到整个字符串中所有符合条件的字符。如果没有g就只会匹配到第一个。
const reg = new RegExp(/ab/ig)
const result = 'abABCDab'.match(reg)
console.log(result) // ['ab', 'AB', 'ab']
g结合i再匹配了一下,忽略了大小写,AB也被匹配进去了。
m (multiple lines)
支持多行匹配,看个例子,简单说明一下m的用法,很少用到。
\n
表示换行,^ab
表示匹配字符串中以ab开头的那一部分。
const reg = new RegExp(/^ab/)
const result = 'ABCD\nab'.match(reg)
console.log(result) // null
如果加一个m,可以看到结果result中 有一个index为5
的属性,证明\n
后的ab
被匹配到了
const reg = new RegExp(/^ab/m)
const result = 'ABCD\nab'.match(reg)
console.log(result) // ['ab', index: 5, input: 'ABCD\nab', groups: undefined]
m的作用就是每遇到一次\n就认为后面的内容是全新的一行,当然也就符合以ab开头的匹配规则。
const reg = new RegExp(/^ab/gim)
const result = 'ABCD\nab'.match(reg)
console.log(result) // ['AB', 'ab']
正则表达式
[ ]
每一个[ ]表示一位,而里面的内容,就是这一位的取值范围
[abc]
从abc中取一个出来,a或者b或者c都符合这个位置的要求
[0a]
0或者a都符合这个位置的要求
const reg = new RegExp(/[ab]/g)
const result = 'ABCDab'.match(reg)
console.log(result) // ['a', 'b']
result匹配到了两个,是因为g修饰符,一个a和一个b,是因为匹配规则是匹配一位,一个[]表示一位,这一位可以是a,也可以是b
[]
里面可以加^
,和之前的^
不同,方括号里的^
表示凡是不在方括号表示范围的字符都可以。
const reg = new RegExp(/[^ab]/g) // 查找字符串中不是a或者不是b的一位字符
const result = 'ABCDab'.match(reg)
console.log(result) //['A', 'B', 'C', 'D']
[]
里面可以加-
,表示一定的范围,如果你想让某一位是数字,难道要[0123456789]
,可以使用[0-9]
-
在其它地方使用都没有特殊意义,只是占一位的字符-
[0-9]
表示这一位是数字0到9都可以
[a-z]
表示这一位是字母a到z都可以
[A-Z]
表示这一位是字母A到Z都可以
[A-z]
表示这一位是字母A到z都可以,这就囊括了所有的字母,但A必须在前面,因为大写字母的ascll码更小,不能[z-A]
,会报错。
const reg = new RegExp(/[^0-9]/g) // 匹配出所有非数字,
const result = '123AB'.match(reg)
console.log(result) // ['A', 'B']
const reg = new RegExp(/[^0-9A-z]/g) // 匹配出所有非数字非字母
const result = '123AB*-'.match(reg)
console.log(result) // ['*', '-']
()
()
可以加 |
,|
表示或
const reg = new RegExp(/(a|b)/g)
const result = 'ABCDab'.match(reg)
console.log(result) // ['a', 'b']
(a|b)
表示|左边的a或者右边的b都符合匹配要求,好像和[ab]没啥区别,
const reg = new RegExp(/(abc|bcd)/ig)
const result = 'ABCDabcd'.match(reg)
console.log(result) //['ABC', 'abc']
(abc|bcd)
表示连着的abc或者连着的bcd都可以
()里面的是左右二选一组,一组可能有多位,而[]里面是范围内选一位。
元字符
.
在正则表达式中某些字母或字母组合具有特殊意义,只列出重要的
元字符 | 特殊意义 |
---|---|
. | 查找单个字符,除了换行符\n 或行终止符\r 。 |
const reg = new RegExp(/./g)
const result = 'AB1\n-\r0'.match(reg)
console.log(result) // ['A', 'B', '1', '-', '0']
w 是word的缩写
元字符 | 特殊意义 |
---|---|
\w | 查找数字或字母,默认一位。和[A-z0-9] 表示意义相同 |
\W | 和\w 相反,查找非数字非字母的字符,默认一位 和[^A-z0-9] 表示意义相同 |
const reg = new RegExp(/\w\w/g) // 匹配所有连续两位是字母或数字的片段
const result = 'AB1\n-\r ba11'.match(reg)
console.log(result) // ['AB', 'ba', 11]
const reg = new RegExp(/\W\W/g) // 匹配所有连续两位是非字母并且非数字的片段
const result = 'AB1\n-\r ba11'.match(reg)
console.log(result) // ['\n-', '\r ']
d 是digit的缩写
元字符 | 特殊意义 |
---|---|
\d | 查找任意数字,默认一位。和[0-9] 表示意义相同 |
\D | 和\d 相反,查找非数字 和[^0-9] 表示意义相同 |
const reg = new RegExp(/\d\d/g) // 匹配所有连续两位是数字的片段
const result = 'AB177b12a'.match(reg)
console.log(result) // ['17', '12']
const reg = new RegExp(/\d\D/g) // 匹配所有连续两位,一位数字连接一位非数字,并且数字在前的片段
const result = 'AB177b12a'.match(reg)
console.log(result) // ['7b', '2a']
s 是 space的缩写
元字符 | 特殊意义 |
---|---|
\s | 查找空格或\n 或\r 或\t 或\v 或\f ,默认一位。 |
\S | 和\s 相反,默认一位 |
const reg = new RegExp(/\s/g)
const result = 'AB1\n-\r\t\v\f 0 '.match(reg)
console.log(result) // ['\n', '\r', '\t', '\v', '\f', ' ', ' ', ' ']
const reg = new RegExp(/\S\s/g)
const result = 'AB1\n-\r\t\v\f 0 '.match(reg)
console.log(result) // ['1\n', '-\r', '0 ']
其它间隙元字符
元字符 | 特殊意义 |
---|---|
\n | 查找换行符 占位 |
\f | 查找换页符 占位 |
\r | 查找回车符 占位 |
\t | 查找制表符 占位 |
\v | 查找垂直制表符 占位 |
不占位修饰符
一般都是都附近的规则有位置上的修饰,比如要求n必须在开头,或必须在结尾,或必须诶着什么,或者不能诶着什么
b是border的缩写
不占位修饰符 | 特殊意义 |
---|---|
\b | 边界字符,一段连续字符 开始的那一位 或者 一段连续字符 结束的那一位 不占位 |
\B | 非边界字符,不占位 |
看例子更容易理解
const reg = new RegExp(/\b\w/g) // 查找与间隙相连,并且间隙在前的字母或数字 一位,因为\b不占位
const result = 'dengxi is 123'.match(reg)
console.log(result) // [d, i, 1]
const reg = new RegExp(/\w\b/g) // 查找与间隙相连,并且字母或数字在前 一位,因为\b不占位
const result = 'dengxi is 123'.match(reg)
console.log(result) // [i, s, 3]
字符串开头,空格,\n
,\r
,\t
,\f
,\v
字符串结尾,这些都算间隙
const reg = new RegExp(/\w\b/g) // 查找与间隙相连,并且字母或数字在前的 一位 字符,因为\b不占位
const result = 'dengxi\nyang\rxi'.match(reg)
console.log(result) // ['i', 'g', 'i']
const reg = new RegExp(/\w\B/g) // 所有后面不跟着间隙的数字或者字母 一位,因为\B不占位
const result = 'dengxi\nyang\rxi'.match(reg)
console.log(result) // ['d', 'e', 'n', 'g', 'x','y','a','n','x']
^
在开头放置表示行开头,在[]中放置表示中括号的范围取反。
不占位修饰符 | 特殊意义 |
---|---|
^n | 找到字符串中以n作为行 开头的那一部分,n可以是一位或者多位,^ 本身不占位 |
[^n] | 找到非n提供范围内的一位字符, ^ 本身不占位 |
\n
是换行,\r
回车,都会出现新的一行
另外修饰符m是能够换行匹配的关键
const reg = new RegExp(/^\w\w/gm)
const result = '12AB1\n11\rbb\tcc\vdd\f01\n02'.match(reg)
console.log(result) // ['12', '11', 'bb', '02']
const reg = new RegExp(/^\w\w/g)
const result = '12AB1\n11\rbb\tcc\vdd\f01\n02'.match(reg)
console.log(result) // ['12']
$
在末尾放置放置,表示在行末尾
不占位修饰符 | 特殊意义 |
---|---|
n$ | 找到字符串中以n作为行 结尾的那一部分,n可以是一位或者多位,$ 本身不占位 |
\n
是换行,\r
回车,都会出现新的一行
另外修饰符m是能够换行匹配的关键
const reg = new RegExp(/\w\w$/gm)
const result = '12AB1\n11\rbb\tcc\vdd\f01\n02'.match(reg)
console.log(result) // ['B1', '11', '01', '02']
const reg = new RegExp(/\w\w$/g)
const result = '12AB1\n11\rbb\tcc\vdd\f01\n02'.match(reg)
console.log(result) // ['02']
?=
和?!
不占位修饰符 | 特殊意义 |
---|---|
(?=n) | 匹配任何其后紧接指定字符串 n 的字符串。 |
(?!n) | 匹配任何其后没有紧接指定字符串 n 的字符串。 |
?=n
要配合小括号使用,否则不生效
const reg = new RegExp(/\w(?=1)/g) // 匹配后面跟着1的数字或字母,(?=1)不占位,所以匹配出来的结果只有1位
const result = '12AB21\n21\rbb\tcc\vdd\f01\n02'.match(reg)
console.log(result) //['2', '2', '0']
const reg = new RegExp(/\w\w(?!\w)/g) // 匹配后面没有数字或字母跟着的 连续两位数字或字母,(?!\w)不占位,所以匹配出来的结果只有2位
const result = '12AB21\n21\rbb\tcc\vdd\f01\n02'.match(reg)
console.log(result) // ['21', '21', 'bb', 'cc', 'dd', '01', '02']
量词
量词本身是不占位的,但是,量词会将临近它的 有符占位数的规则 做一个乘法,比如 /\w{2}/
的意义就相当于/\w\w/
,就是将\w
给乘以2。
量词 | 特殊意义 |
---|---|
n{X} | 匹配包含 X 个 n 的序列的字符串。 |
n{X,Y} | 匹配包含 X 至 Y 个 n 的序列的字符串。 |
n{X,} | 匹配包含至少 X 个 n 的序列的字符串。 |
X和Y都是数字,前面的小,后面的大,n表示任意拥有占位数的正则规则。
const reg = new RegExp(/\w{2}/g) // 匹配两位,连续的是字母或数字的字符串
const result = '12AB1\n11\rbb\tcc\vdd\f01\n02'.match(reg)
console.log(result) // ['12', 'AB', '11', 'bb', 'cc', 'dd', '01', '02']
正则表达式的贪婪原则,能匹配长的,就不匹配短的,下面的规则中,是两位或者三位都可以,但优先查看是否三位满足正则的要求。
const reg = new RegExp(/\w{2,3}/g) // 匹配两位或者三位,优先匹配三位,连续每个字符都是数字或者字母的字符串
const result = '12AB1\n11\rbb\tcc\vdd\f01\n02'.match(reg)
console.log(result) // ['12A', 'B1', '11', 'bb', 'cc', 'dd', '01', '02']
至少两位,尽可能多位
const reg = new RegExp(/\w{2,}/g) // 匹配 至少连续两位的字符串,尽可能长,要求每一位都是字母或数字
const result = '12AB1\n11\rbb\tcc\vdd\f01\n0244'.match(reg)
console.log(result) // ['12AB1', '11', 'bb', 'cc', 'dd', '01', '0244']
下限设置为0
const reg = new RegExp(/\w{0,4}/g) // 匹配整个字符串,最多4位,至少0位,表示可以为空,0乘以任何东西都是0,所以匹配出了空。
const result = '12AB1\n11\rbb\tcc\vdd\f01\n0244'.match(reg)
console.log(result) // ['12AB', '1', '', '11', '', 'bb', '', 'cc', '', 'dd', '', '01', '', '0244', '']
有的人可能会尝试着设置一个上限,而不设置下限,下限连0都不是,其实没什么意义,也没有这个规则
const reg = new RegExp(/\w{, 4}/g)
const result = '12AB1\n11\rbb\tcc\vdd\f01\n0244'.match(reg)
console.log(result) // null
量词 | 特殊意义 |
---|---|
n+ | 匹配任何包含至少一个 n 的字符串。相当于 n{1,} |
n* | 匹配任何包含零个或多个 n 的字符串。相当于 n{0,} |
n? | 匹配任何包含零个或一个 n 的字符串。相当于n{0, 1} |
一样有贪婪原则
const reg = new RegExp(/\w*/g) // 匹配整个字符串,至少0位,表示可以为空,0乘以任何东西都是0,所以匹配出了空。
const result = '12AB1\n11\rbb\tcc\vdd\f01\n0244'.match(reg)
console.log(result) ['12AB1', '', '11', '', 'bb', '', 'cc', '', 'dd', '', '01', '', '0244', '']
const reg = new RegExp(/12?/g) // 匹配整个字符串,至少1位1,2可能乘以0不存在,2可能乘以1为一位,
const result = '12AB1\n11\rbb\tcc\vdd\f01\n12222222'.match(reg)
console.log(result) // ['12', '1', '1', '1', '1', '12']
const reg = new RegExp(/12+/g) // 匹配整个字符串,至少1位1,1位2,2可能乘以1,2可能乘以很多位,贪婪原则
const result = '12AB1\n11\rbb\tcc\vdd\f01\n12222222'.match(reg)
console.log(result) // ['12', '12222222']
正则的反向引用 (n)\数字
这个非常有用,很多人都不知道正则还有这种用法,可能学到上面就已经结束了,在 w3c school中,也从来没有提过这种用法。
想要获取字符串中,所有形如aabb的字符串,1122
可以,ccdd
也可以,只要第一位和第二位相同,第三位和第四位相同即可。
/\w{2}\w{2}/
?这肯定不能解决,每一次\w都是独立随机的,这相当于\w\w\w\w
确实是四位,但不能保证第一位和第二位相同啊。
所以为了解决形如aabb的问题,就必须得获取第一位的实际内容,然后给第二位,获取第三位的实际内容,给第四位。
/(\w)\1(\w)\2/
用法(n)\数字
,如果是第一次使用,那数字就是1,如果是第二次使用,数字就是2,并且\1本身也是占位的,所以/(\w)\1(\w)\2/
这就是四位。
\数字
会重复(n)
里n
的实际内容,不是正则规则上的重复,而是匹配出字符串内容的重复。
const reg = new RegExp(/(\w)\1(\w)\2/g)
const result = 'adad ccdd cccc bbpp fhajw'.match(reg)
console.log(result) // ['ccdd', 'cccc', 'bbpp']
RegExp 对象方法
常用的方法就俩,exec()
and test()
exec()
是 execute的缩写
execute就是执行,所以exec只会执行依次匹配,正则表达式后面的g没啥用
const reg = new RegExp(/(\w)\1(\w)\2/g)
const result = reg.exec('adad ccdd cccc bbpp fhajw')
console.log(result) // ['ccdd', 'c', 'd', index: 5, input: 'adad ccdd cccc bbpp fhajw', groups: undefined]
但是exec会返回一些特殊的东西,其中数组的第一位和第二位很重要,它们对应的就是正则反向引用 匹配到的真实字符。
test()
test()
传入需要匹配的字符串,如果字符串符合正则表达式的规则,就返回true
,如果字符串不符合,就返回false
const reg = new RegExp(/(\w)\1(\w)\2/g)
const result = reg.test('adad ccdd cccc bbpp fhajw')
const rsult1 = reg.test('dengxi yangxi')
console.log(result,rsult1) // true false
支持正则表达式的 String 对象的方法
方法名 | 介绍 |
---|---|
search | 检索与正则表达式相匹配的值。 |
match | 找到一个或多个正则表达式的匹配。 |
replace | 替换与正则表达式匹配的子串。 |
split | 把字符串分割为字符串数组。 |
search()
最没用的就是search,返回的是第一个符合正则规则所在字符的位置
正则里面的g没用,只匹配第一个,也只返回第一个,ccdd是能匹配到的第一个,c所在的下标是5,所以结果返回5,如果整个字符串都没找到返回-1
const reg = new RegExp(/(\w)\1(\w)\2/g)
const result = 'adad ccdd cccc bbpp fhajw'.search(reg)
const result1 = 'dengxi yangxi'.search(reg)
console.log(result,result1) // 5 -1
match()
用过很多次了,很实用。
split()
将符合正则规则的字符串片段作为分界限,拆分字符串位数组。通常使用split都是传入固定的字符串,作为分界,但有了正则后,只要这些分界有某种规律,它们不必相同,也能直接拆成数组。
const reg = new RegExp(/\W/g)
const result = '12FSAF#FJA*FJD*JDKA/DASF/FASEF'.split(reg)
const result1 = 'my name is dengxi'.split(reg)
console.log(result) //['12FSAF', 'FJA', 'FJD', 'JDKA', 'DASF', 'FASEF']
console.log(result1) //['my', 'name', 'is', 'dengxi']
replace()
真正的王者,最实用的方法,一个字就是香。
我想获取当前的时间,并且以 year-month-day hh:mm:ss的格式返回。
function getTime() {
const NowDate = new Date()
const time = NowDate.toString() // 'Thu Nov 16 2023 17:08:25 GMT+0800 (中国标准时间)'
const month = NowDate.getMonth() // 这里偷懒了,用这种方法获取了月份
const reg = /.* (\d{2}) (\d{4}) ((\d|:){8}) .*/ // 这个正则能匹配到整个字符串,但将其中关键信息抽取了出来
const result = time.replace(reg, function($,$1,$2,$3){
console.log($) // Thu Nov 16 2023 17:27:51 GMT+0800 (中国标准时间)
console.log($1) // 16
console.log($2) // 2023
console.log($3) // 17:15:32
return `${$2}-${month + 1}-${$1} ${$3}`
})
return result // '2023-11-16 17:27:51'
}
将 deng-xi-and-yang-xi
转变为小驼峰命名 dengXiAndYangXi
将诶着-的字符找出来,替换成对应的大写就可以了,一看就跟
function changeStringName(str) {
const reg = new RegExp (/-(\w)/g)
const result = str.replace(reg,function($,$1) {
console.log($)
console.log($1)
return $1.toUpperCase()
})
return result
}
var a = changeStringName('deng-xi-and-yang-xi')
console.log(a) // dengXiAndYangXi