# 第一章 应用场景
应用场景
- 正则的基本应用场景作用就是搜索和替换,精通以后遇到字符串搜索替换就可以首先想到正则的解决方案
- 同一个问题经常会有多种正则解决方案
- JavaScript正则引擎是perl,不支持POSIX字符类
- 找car单词
var str = "car incar Car inmycar car";
var reg = /\bcar\b/ig;
console.log(str.match(reg)); // [ 'car', 'Car', 'car' ]
1
2
3
4
2
3
4
- 将字符串的超链接变成HTML可点形式
var str = "this is my address:http://www.baidu.com/ car incar Car inmycar";
var reg = /\b(http|https):\/\/(?:www.)*?[\w]+?.(com|cn|org)\//ig;
console.log(str.replace(reg,(match) => `<a href='${match}'>${match}</a>`));
// this is my address:<a href='http://www.baidu.com/'>http://www.baidu.com/</a> car incar Car inmycar
1
2
3
4
5
2
3
4
5
# 第二章 单个字符
- 【.】表示任意字符,但要匹配换行符等需要加标识符s
- 匹配符号【.】:本身加斜杠【\ .】
- 【\b】单词间的间距。
- 【\B】字母间的间距。
- 找到所有的c.t
const str = 'cat cot ctt caat';
const reg = /c.t/g;
console.log(str.match(reg)); // ['cat', 'cot', 'ctt']
1
2
3
4
2
3
4
- 找到所有的张某
const str = '张三 李四 张 王五 张志文 张靓颖';
const reg = /张.*?(?=\s|$)/g;
console.log(str.match(reg)); // [ '张三', '张', '张志文', '张靓颖' ]
1
2
3
4
2
3
4
- 找到所有的文件名:.a文件:na.txt、sa.txt..
const str = `ana.txt
na.txt
nax.txt
sa.txt
`
const reg = /^.a\.\w+\b/gm;
console.log(str.match(reg)); // ['na.txt', 'sa.txt']
1
2
3
4
5
6
7
2
3
4
5
6
7
# 第三章 区间
区间
- 【[]】中括号内可以写取值区间。如:[ sa ]
- 全局不区分大小写可以用【i】,局部不区分大小写可以写[a-zA-Z]
- JS标识符【\w】代表区间[a-zA-Z0-9_],【\W】取反
- 区间内【^】开头代表排除这个区间
- 区间内空格匹配一个空格
- 只要sa.txt/na.txt
const str = `ca.txt
nan.txt
sa.txt
ana.txt
na.txt
`;
const reg = /^[ns].\.txt/mg;
console.log(str.match(reg)); // [ 'sa.txt', 'na.txt' ]
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
- 匹配RegExp或regexp
const str = '正则一般写作RegExp或者regexp';
const reg = /[Rr]eg[Ee]xp/g;
console.log(str.match(reg)); // ['RegExp', 'regexp']
1
2
3
2
3
- 匹配所有数字字母
const str = 'Word汉字word汉字123_';
const reg1 = /\w+\b/g;
const reg2 = /[a-zA-Z0-9]+\b/g
console.log(str.match(reg1)); // [ 'Word', 'word', '123_' ]
console.log(str.match(reg2)); // [ 'Word', 'word' ]
1
2
3
4
5
6
2
3
4
5
6
- 查找所有RGB颜色值
const str = `
.header {
color: #969896;
}
#b {
color: #c66;
}
div {
color: #de935f;
}
.d {
color: #F0C674;
}`;
const reg = /(?<=:\s)#[A-Fa-f0-9]{3,6}/g;
console.log(str.match(reg)); // [ '#969896', '#c66', '#de935f', '#F0C674' ]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
- 找到所有的【sX.txt】,X不能是数字。例:sa.txt/sb.txt
const str = `
sa.txt
s1.txt
sb.txt
`
const reg = /s[^1-9]\.txt/gim;
console.log(str.match(reg)); // [ 'sa.txt', 'sb.txt' ]
1
2
3
4
5
6
7
2
3
4
5
6
7
- 匹配空格
const str = '我 中间 的空格 不固定 !';
const reg = /[ ]+/g;
console.log(str.match(reg)); // [ ' ', ' ', ' ', ' ' ]
1
2
3
2
3
# 第四章 元字符
常用元字符
- 匹配元字符本身需要转义【\ (\ )】
元字符 | 含义 |
---|---|
() | 捕获组 |
[] | 区间 |
. | 任意字符 |
\ | 转义字符 |
+ | 一到多个匹配 |
* | 0到多个匹配 |
? | 1.非贪婪匹配 2.环视 3.位置关系匹配 4.0个或1个匹配 |
^ | 1.文章/行/单词开头 2.范围取反 |
$ | 文章/行/单词结尾 |
类元字符
- 类元字符代表某一类字符,十分有用
元字符 | 含义 |
---|---|
\s | 空格、非打印字符(换行、制表符类)[\f\n\r\t\v] |
\S | 【\s】取反,所有打印字符 |
\w | 字母数字下划线[a-zA-Z0-9_] |
\W | 非字母数字下划线[^a-zA-Z0-9_] |
\d | 所有数字 |
\D | 所有非数字 |
\b | 所有单词分隔(不匹配出空格,只匹配出单词结束) |
\B | 所有字母分隔 |
\f | 换页 |
\n | 换行 |
\r | 回车 |
\t | 制表符 |
\v | 垂直制表符 |
- POSIX字符类JS不支持
- 转义元字符:匹配出数组
const str = `
const arr = [1, 2, 3, [4, 5]];
console.log(arr)`
const reg = /\[.*\](?=\s|;)/g;
console.log(str.match(reg)); // [ '[1, 2, 3, [4, 5]]' ]
1
2
3
4
5
6
2
3
4
5
6
- 【\s\S】:数据去空格/换行
const str = `大家
好,
我是 hdy
!`
const reg = /\s/g;
console.log(str.replace(reg, '')); // 大家好,我是hdy!
1
2
3
4
5
6
2
3
4
5
6
- 【\d\D】:把数字分离出来
const str = '我今年18岁';
const reg1 = /\d+/g;
const reg2 = /\D+/g;
console.log(str.match(reg1)); // [ '18' ]
console.log(str.match(reg2)); // [ '我今年', '岁' ]
1
2
3
4
5
2
3
4
5
- 【\b】和【\B】的区别:匹配出所有单词。
const str = 'I love this world!';
const reg1 = /\w+\b/gi;
const reg2 = /\w+\B/gi;
console.log(str.match(reg1)); // [ 'I', 'love', 'this', 'world' ]
console.log(str.match(reg2)); // [ 'lov', 'thi', 'worl' ]
1
2
3
4
5
6
2
3
4
5
6
# 第五章 重复匹配
重复匹配
字符 | 含义 |
---|---|
+ | 贪婪,1个以上 |
+? | 非贪婪,1个以上 |
* | 贪婪,0个以上 |
*? | 非贪婪,0个以上 |
? | 0个或1个 |
{2} | 2次 |
{2,} | 2次及以上 |
{2,4} | 2-4次 |
贪婪模式
- 有多个匹配成功情形时,是选择最多的匹配方式(贪婪)还是最少的匹配方式(非贪婪)
- 【贪婪/非贪婪】匹配出对象
// 只要params后面的结果对象,但是有对象嵌套的情况
const str = 'baiduboxapp://setquery?params={"code":200, "data": {"name":"hdy", "pets":{"dog": "小黄", "cat": "小花"}}}';
const reg1 = /(?<=params=)\{.*\}/g;
const reg2 = /(?<=params=)\{.*?\}/g;
console.log(str.match(reg1)); // ['{"code":200, "data": {"name":"hdy", "pets":{"dog": "小黄", "cat": "小花"}}}']
// 匹配错误,少了花括号
console.log(str.match(reg2)); // ['{"code":200, "data": {"name":"hdy", "pets":{"dog": "小黄", "cat": "小花"}']
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
- 【贪婪 + \w + 转义.】匹配URL
const str = '我的网址是:www.hao123.com';
const reg = /[\w\.]+/gi;
console.log(str.match(reg)); // [ 'www.hao123.com' ]
1
2
3
4
2
3
4
- 【?】复杂一点的URL
const str = '我的网址是:https://www.baidu.com 或者http://www.baidu.com 或者www.baidu.com';
const reg = /(https?:\/\/)?[\w\.]+/gi;
console.log(str.match(reg)); // [ 'https://www.baidu.com', 'http://www.baidu.com', 'www.baidu.com' ]
1
2
3
4
2
3
4
- 尾部处理:匹配邮箱
const str = 'My Email is 986005715@qq.com ,do you remember?Another one is huangdeyu2020@163.com.Please call me!';
const reg1 = /\b[\w\.]+?@[\w\.]+\w+(?=[\.,!\b\s])/g;
// 错误尾部处理
const reg2 = /\b[\w\.]+?@[\w\.]+[\w\.]+/g;
console.log(str.match(reg1)); // [ '986005715@qq.com', 'huangdeyu2020@163.com' ]
console.log(str.match(reg2)); // [ '986005715@qq.com', 'huangdeyu2020@163.com.Please' ]
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
- 【{min, max}】匹配日期串
// 第三个日期不符合规范
const str = `
2021/09/10
21/9/1
2/2/2
`;
const reg = /\d{2,4}\/\d{1,2}\/\d{1,2}/g;
console.log(str.match(reg)); // [ '2021/09/10', '21/9/1' ]
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# 第六章 位置匹配
位置符号
符号 | 含义 |
---|---|
\b | 单词边界(位置符号不占实际的字符) |
\B | 非单词边界(位置符号不占实际的字符) |
^ | 字符串开头/多行模式下行开头 |
$ | 字符串结尾/多行模式下行结尾 |
- 【\b\B】边界详解
- 单词边界使用:替换cat
const str = 'The cat scatter the food.But I love the cat.'
// 错误:不使用单词边界,会匹配到包含单词
const reg1 = /cat/g;
console.log(str.replace(reg1,'dog')); // The dog sdogter the food.But I love the dog.
// 使用单词边界
const reg2 = /\bcat\b/g;
console.log(str.replace(reg2,'dog')); // The dog scatter the food.But I love the dog.
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
- 【^】匹配开头:检测是否正确的html5文档
// 注:前面有空格、换行
const str = `
<!DOCTYPE html>
<html lang="en">
<head>
</head>
<body>
</body>
</html>
`
const reg = /^\s*<\!DOCTYPE html>/;
console.log(reg.test(str)); // true
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
- 标识符【m】:多行匹配
const str = `
hdy
is
happy
!`
const reg1 = /^h.+?\b/g;
console.log(str.match(reg1)); // null
const reg2 = /^h.+?\b/gm;
console.log(str.match(reg2)); // [ 'hdy', 'happy' ]
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# 第七章 子表达式
子表达式
- 长度限制字符【+】【*】【{}】都限制了紧挨着的一个字符的次数,如果要限制多个字符,就需要用子表达式【()】
- 子表达式捕获的项也叫
捕获组
,要是不想存储捕获组用非捕获性分组
【(?: )】 - 子表达式可以嵌套使用
- 在没有必要的时候不要存储捕获组,对正则的性能有影响
- 删掉所有的空格字符【 】
const str = 'I am hdy.';
// 直接用限位符只是限制了分号:【;】
const reg1 = / +/g;
console.log(str.match(reg1)); // [ ' ', ' ', ' ', ' ' ]
// 子表达式后面的限制符:限制子表达式的重复次数
const reg2 = /( )+/g;
console.log(str.match(reg2)); // [ ' ', ' ' ]
console.log(reg2.exec(str)); // [ ' ',' ',index: 1,input: 'I am hdy.', groups: undefined]
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
- 子表达式:匹配IP地址
const str = 'I am hdy,my phone is 15542640501,my ip is 152.16.177.169.'
const reg = /(\d{1,3}\.){3}\d{0,3}/;
console.log(str.match(reg)[0]); // 152.16.177.169
1
2
3
2
3
- 子表达式:匹配年份
const str = 'I am birth in 1996,but many people birth after 2000.';
// 错误,优先级的原因,关系符会查看左右两边的内容,所以关系符或【|】变成了【19 或 20\d{2}】
const reg1 = /19|20\d{2}/g;
console.log(str.match(reg1)); // [ '19', '2000' ]
const reg2 = /(19|20)\d{2}/g;
console.log(str.match(reg2)); // [ '1996', '2000' ]
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
- 子表达式:筛选出qq邮箱或163邮箱
const str = 'I have 3 email account.986005715@qq.com and huangdeyu2020@163.com and huangdeyu@baidu.com.';
const reg = /\w+@(qq|163)\.\w+/gi;
console.log(str.match(reg)); // [ '986005715@qq.com', 'huangdeyu2020@163.com' ]
1
2
3
2
3
- 非捕获性分组
const str = '向后查看匹配内容向前查看';
const reg1 = /匹配内容(?=向前查看)/g;
const reg2 = /匹配内容(?:向前查看)/g;
const reg3 = /(?:向后查看)匹配内容/g;
console.log(reg1.exec(str)); // [ '匹配内容', index: 4, input: '向后查看匹配内容向前查看', groups: undefined ]
console.log(reg2.exec(str)); // [ '匹配内容向前查看', index: 4, input: '向后查看匹配内容向前查看', groups: undefined ]
console.log(reg3.exec(str)); // [ '向后查看匹配内容', index: 0, input: '向后查看匹配内容向前查看', groups: undefined ]
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# 第八章 反向引用
反向引用
- 反向引用支持正则引用之前匹配的结果
- 下标从1开始,如【\1】代表第一个捕获组
- JS替换操作中用的是【$】加捕获组下标,嵌套捕获组最外层下标最小
- 反向引用:匹配HTML标题
const str = `
<h1>我是标题</h1>
<div>盒子,懂不?</div>
<H2>错误标签,不匹配!</H4>
<h3>嵌套,会吗?</h3>
<image/>
`;
const reg = /<[Hh]([1-6])>.*?<\/[Hh]\1>/gi;
console.log(str.match(reg)); // [ '<h1>我是标题</h1>', '<h3>嵌套,会吗?</h3>' ]
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
- 反向引用做替换
- 替换字符串中的【$\d】,\d是捕获组下标
# 第九章 环视
环视
- 匹配时能够观察上下文,在正确位置的内容,并且不用子表达式来存储多余的结果。
模式 | 含义 |
---|---|
(?=) | 肯定向前查看 |
(?!) | 否定向前查看 |
(?<=) | 肯定向后查看 |
(?<!) | 否定向后查看 |
(?: ) | 非捕获性分组 |
- 注:向前指在匹配内容前面的(已经出现了的)字符,向后指在匹配内容后面的(还未出现的)内容
const str = '向后查看匹配内容向前查看';
const reg1 = /匹配内容(?=向前查看)/g;
const reg2 = /(?<=向后查看)匹配内容/g;
console.log(str.match(reg1)); // [ '匹配内容' ]
console.log(str.match(reg2)); // [ '匹配内容' ]
1
2
3
4
5
6
2
3
4
5
6
?
- 书上81页说JS不支持向后查看,但是经测试是可以的
- 两个环视放在一起后面的的生效
# 第十章 嵌入式条件
嵌入式条件
- 嵌入式条件主要包括这两种情况:
- 根据反向引用来进行条件处理
- 根据环视来进行条件处理
- JS好像不支持嵌入式条件?
const str = `
1
<a>
1
</a>
`;
// 第一个捕获组有的情况下再进行第二个捕获组的匹配,JS好像不支持
const reg = /(<a>\s*)?1(?(1)?\s*<\/a>)?/gi;
console.log(str.match(reg));
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10