正则表达式
星月 3/27/2022 js
正则表达式中分组可以分为捕获分组和非捕获分组。
捕获分组很简单,用()
来表示。
非捕获分组,则基本可以分为五种:
(?:)
最基础也是最常见的非捕获分组。我们可以使用
(?:)
来进行非捕获的分组,因为很多时候我们需要使用分组,比如(\d{3})+
,但我们又并不想捕获这个分组,这时候就可以使用(?:)
了。(?=)
零宽正向先行断言(zero-width positive lookahead assertion)。(?!)
零宽负向先行断言。(?<=)
零宽正向后行断言。(?<!)
零宽负向后行断言。
零宽(zero-width)表示着它匹配的是一个位置,就像^
或$
又或者是\b
一样,而不是匹配字符。
这里的先行,表示着位置的右边;后行表示着位置的左边。而正向和负向,则就是有与无的关系了。
另外默认情况下.+
是会进行贪婪匹配,而量词后加上?会进行惰性匹配,比如.+?
。
# 常用字符
当使用构造函数创造正则对象时,需要常规的字符转义规则**(在前面加反斜杠 \)**。比如,以下是等价的:
var re = new RegExp("\\w+");
var re = /\w+/;
1
2
2
字符串的match
可以获取所有匹配正则的结果,但获取不到对应的捕获值。通常想捕获都是用正则表达式的exec
方法,但要捕获全部的话需要进行循环exec
。
es2020
新增了一个字符串方法matchAll
,相当于循环执行了exec
。
const reg = /[a-c]/g
const str = 'abc'
for (let i of str.matchAll(reg)) console.log(i)
1
2
3
2
3
# 正则题目
# 匹配URL参数
// 正则
function getUrlParams(name) {
const reg = new RegExp(`(?:^|&)${name}=([^&]*)(?:$|&)`)
const match = location.search.substr(1).match(reg)
if (match) {
return match[1]
}
}
function getUrl(key) {
let map = {}
let ret
const reg = /(?:^|&)(.*?)=(.*?)(?=&|$)/g
const search = 'name=akara&age=21&type=normal&sex=male'
while (ret !== null) {
ret = reg.exec(search)
if (ret) {
map[ret[1]] = ret[2]
}
}
return map[key]
}
// split
function getUrlParams(name) {
const arr = location.search.substr(1).split('&')
let obj = {}
arr.forEach(item => {
let tempArr = item.split('=')
obj[tempArr[0]] = tempArr[1]
})
return obj[name]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# 匹配cookie参数
function getUrlParams(name) {
const reg = new RegExp(`(\\s|^)${name}=([^;]*)($|;)`) // \s 前面要多一个 \
const match = document.cookie.match(reg)
if (match) {
return match[2]
}
}
1
2
3
4
5
6
7
2
3
4
5
6
7
# 域名判断
判断当前域名是否为qq.com,或者其子域名
function isMatch(url) {
return /^https?:\/\/(.+\.)?qq\.com/.test(url)
}
isMatch('http://a.qq.com') // true
isMatch('https://qq.com') // true
1
2
3
4
5
2
3
4
5
# 电话号码判断
const isPhone = (str) => {
const reg = /^1[34578]\d{9}$/g
return reg.test(str)
}
1
2
3
4
2
3
4
# 驼峰化
将aaa-bbb-ccc
转换为驼峰aaaBbbCcc
function toCamel(str) {
return str.replace(/-\w/g, (s) => {
return s.slice(1).toUpperCase()
})
}
// \w 匹配数字,字母与下划线
1
2
3
4
5
6
2
3
4
5
6
# 数字的千分位分割
// 正则,注意使用到了?=先行断言,?:为非捕获,可加可不加
function format(num) {
return num.toString().replace(/(?=(?<!^)(?:\d{3})+$)/g, ',')
}
// function format(num) {
// const reg = /\d{1,3}(?=(?:\d{3})+$)/g
// return num.toString().replace(reg, '$&,')
// }
// const format = (number) => {
// const str = number + ''
// return str.replace(/(?=(?!^)(\d{3})+$)/g, ',')
// // return str.replace(/\d{1,3}(?=(\d{3})+$)/, '$&,')
// }
// 也可以用toLocaleString轻松实现
function format(num) {
return num.toLocaleString()
}
// 或者用数字来分割
function format (num) {
let arr = []
while (num >= 1000) {
let value = num % 1000
num = num / 1000
if (value >= 100) {
value = '' + value
} else if (100 > value && value >= 10 ){
value = `0${value}`
} else {
value = `00${value}`
}
arr.unshift(value)
}
num = '' + num
arr.unshift(num)
return arr.join(',')
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# 替换元素
把非P元素替换成P元素 <div></div> => <p></p>
const replaceP = (str) => {
return str.replace(/<(\/)?.*?>/g, '<$1p>')
}
1
2
3
2
3