背景
在开发中处理字符串的场景非常常见,而正则作为专业的文本模式匹配工具,可谓是大大的提高了我们处理字符串的能力和效率。但是在业务中使用的时候,因为没有系统的去梳理过正则,简单的还好,稍微复杂一点的,就需要问ai,但ai给出的解法,还需要自己了解和验证,所以还得对不熟悉的点去重新翻阅文档,效率低,自己脑海中也没有对个知识行成较好的记忆。所以为了解决这些痛点,整理归纳一下正则。
说明:各个编程语言的正则规则大致相同,但也会有所差异,所以本文主要围绕javascript中的正则展开.
基本知识
pattern(模式):一列普通字符和元字符组成flags(修饰符):用于改变正则表达式匹配行为的特殊指令
创建
字面量:/pattern/flags
- 编译时机:代码解析阶段
- 性能:好
const reg = /ab+c/i; // 字面量形式
构造函数:new RegExp(pattern[, flags])
- 编译时机:运行时编译
- 性能:差(如每次循坏都要重新编译)
// 首个参数为字符串模式的构造函数
new RegExp("ab+c", "i");
// 需要常规的字符转义规则(在前面加反斜杠\)
const re = new RegExp("\\w+");
const re = /\w+/;
元字符
具有特殊含义的字符,它们不表示字面意义,而是用于控制匹配模式。
基本字符
.(点号)
匹配除
\n外的任意单个字符,其实回车符\r也不匹配
console.log(/a.c/.test('aac')); // true
console.log(/a.c/.test('a\tc')); // true
console.log(/a.c/.test('a\rc')); // false
console.log(/a.c/.test('a\nc')); // false
\(反斜杠)
转义字符,使后面的字符失去特殊含义
console.log(/\./.test('.')); // true
console.log(/\./.test('a')); // false
量词
?(问号)
匹配前面的子表达式零次或一次
console.log(/ab?c/.test('ac')); // true;
console.log(/ab?c/.test('abc')); // true
console.log(/ab?c/.test('abbc')); // false
*(星号)
匹配前面的子表达式零次或多次
console.log(/ab*c/.test('ac')); // true
console.log(/ab*c/.test('abc')); // true
console.log(/ab*c/.test('adc')); // false
+(加号)
匹配前面的子表达式一次或多次
console.log(/ab+c/.test('abc')); // true
console.log(/ab+c/.test('abbc')); // true
console.log(/ab+c/.test('ac')); // false
{}(花括号)
自定义匹配次数
{n}:精确匹配n次
{n,}:至少匹配n次
{n,m}:匹配n-m次
// 精确匹配
console.log(/ab{2}/.test('abb')); // true
console.log(/ab{2}/.test('ab')); // false
// 至少匹配
console.log(/ab{2,}/.test('abb')); // true
console.log(/ab{2,}/.test('abbb')); // true
console.log(/ab{2,}/.test('ab')); // false
// 匹配区间
console.log(/ab{2,3}/.test('abb')); // true
console.log(/ab{2,3}/.test('abbb')); // true
console.log(/ab{2,3}/.test('ab')); // false
console.log(/ab{2,3}c/.test('abbbbc')); // false
分组、选择字符、字符组
()(圆括号)
定义子表达式或捕获组
console.log(/(ab)+c/.test('abc')); // true
console.log(/(ab)+c/.test('ababc')); // true
console.log(/(ab)+c/.test('bc')); // false
|(竖线)
表示"或"关系, 作用多个字符, 建议用括号括起来
console.log(/abc|adc/.test('abc')); // true
console.log(/abc|adc/.test('adc')); // true
console.log(/abc|adc/.test('abadc')); // false
[](方括号)
定义字符集合,匹配其中任意一个字符
console.log(/[abc]/.test('a')); // true
console.log(/[abc]/.test('b')); // true
console.log(/[abc]/.test('c')); // true
[]内部特殊字符
^(否定字符)
匹配不在方括号中的任意字符
// 匹配除a,b,c外的任意一个字符
console.log(/[^abc]/.test('a')); // false
-(连字符)
匹配方括号中范围字符
// 匹配a,b,c中的任意一个字符
console.log(/[a-c]/.test('b')); // true
注: []内除^和-外,还有预定义字符组 和 转义字符生效外,其他元字符 都表示字面量
预定义字符组
\d:匹配任意数字,等价于[0-9]\D:匹配任意非数字,等价于[^0-9]\w:匹配任意单词字符(字母、数字、下划线),等价于[a-zA-Z0-9_]\W:匹配任意非单词字符,等价于[^a-zA-Z0-9_]\s:匹配任意空白字符,等价于[\n\r\t\v\f]\S:匹配任意非空白字符,等价于[^\n\r\t\v\f]
位置(边界)匹配字符
位置:相邻字符之间的位置。
^(脱字符)
匹配字符串的开始位置
console.log(/^abc/.test('abcd')); // true
console.log(/^abc/.test('abcdefg')); // true
console.log(/^abc/.test('aba')); // false
$(美元符)
匹配字符串的结束位置
console.log(/abc$/.test('dabc')); // true
console.log(/abc$/.test('aabc')); // true
console.log(/abc$/.test('adbc')); // false
\b(单词边界符)
匹配单词边界
^和\w之间的位置\w和\W之间的位置\w和$之间的位置
console.log(/\bcat\b/.test('cat demo')); // true
console.log(/\bcat\b/.test('category')); // false
\B(非单词边界符)
匹配非单词边界
\w和\w之间的位置\W和\W之间的位置^和\W之间的位置\W和$之间的位置
console.log(/\Bcat\B/.test('scategory')); // true
console.log(/\Bcat\B/.test('category')); // false
console.log(/\Bcat\B/.test('cat')); // false
断言(位置条件判断)
?=(先行断言)
检查当前位置之后是否匹配pattern
命名解释
- 引擎执行方向:正则表达式引擎通常从左到右扫描字符串
- 当引擎扫描到某个位置时,它需要 "向前看"(Lookahead)来判断当前位置是否满足断言条件,对字符而言,它是相对位置在后面的
const res = 'abcd'.replace(/(?=b)/, '_');
console.log(res); // a_bcd
// 全局模式
const res2 = 'abcd'.replace(/(?=b)/g, '_');
console.log(res2); // a_bcd
匹配机制
- 位置1(^):后面是a,匹配失败
- 位置2(a,b):后面是b,匹配成功
- 位置3(b,c):后面是c,匹配失败
- 位置4(c,d):后面是d,匹配失败
- 位置5($):后面为空,匹配失败
?!(负先行断言)
匹配后面不跟着 pattern 的位置。
const res = 'abcd'.replace(/(?!b)/, '_');
console.log(res); // _abcd
// 全局模式
const res = 'abcd'.replace(/(?!b)/g, '_');
console.log(res); // '_ab_c_d_'
匹配机制
- 位置1(^):后面是a,a!=b,匹配成功
- 位置2(a,b之间):后面是b,b=b,匹配失败
- 位置3(b,c之间):后面是c,c!=b,匹配成功
- 位置4(c,d之间):后面是d,d!=b,匹配成功
- 位置5($):后面是'',''!=b,匹配成功
?<=(后行断言)
检查当前位置之前是否匹配pattern
命名解释
- 引擎执行方向:正则表达式引擎通常从左到右扫描字符串
- 当引擎扫描到某个位置时,它需要 "向后看"(Lookahead)来判断当前位置是否满足断言条件
const res = 'abcd'.replace(/(?<=b)/, '_');
console.log(res); // ab_cd
// 全局模式
const res = 'abcd'.replace(/(?<=b)/, '_');
console.log(res); // ab_cd
匹配机制
- 位置1(^):前面无字符,匹配失败
- 位置2(a,b):前面是a,匹配失败
- 位置3(b,c):前面是b,匹配成功
- 位置4(c,d):前面是c,匹配失败
- 位置5($):前面是d,匹配失败
?<!(负后行断言)
位置之前不跟着pattern
const res = 'abcd'.replace(/(?<!b)/, '_');
console.log(res); // _abcd
// 全局模式
const res = 'abcd'.replace(/(?<!b)/g, '_');
console.log(res); // _a_bc_d_
匹配机制
- 位置1(^):前面无字符,匹配成功
- 位置2(a,b):前面是a,匹配成功
- 位置3(b,c):前面是b,匹配失败
- 位置4(c,d):前面是c,匹配成功
- 位置5($):前面是d,匹配成功
非捕获&具名捕获
?:(非捕获)
仅保留括号的功能,但不存储捕获组的内容,因此能提升正则表达式的效率
const reg = /1(\d)/;
const str = "12134";
console.log(reg.exec(str));
// [ '12', '2', index: 0, input: '12134', groups: undefined ]
// 不存储捕获组内容
const reg = /1(\d)/;
const str = "12134";
console.log(reg.exec(str));
// [ '12', index: 0, input: '12134', groups: undefined ]
?<name>具名捕获
给捕获组进行命名,使用返回捕获结果的正则方法时,存储在groups中
const reg = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const matchObj = reg.exec("2024-05-15");
if (matchObj) {
console.log(matchObj.groups); // 输出: { year: '2024', month: '05', day: '15' }
console.log(matchObj.groups.year); // 输出: '2024'
console.log(matchObj.groups.month); // 输出: '05'
console.log(matchObj.groups.day); // 输出: '15'
}
其他元字符
\n(换行符)
匹配换行符(Line Feed)
- ASCII 码值:10(十进制)或 0x0A(十六进制)
- 表示文本行的结束,光标移到下一行的开始位置
- Unix/Linux/MacOS
- 使用
\n(LF)作为换行符 - 文件中的换行符显示为单个字符
- 使用
\r(回车符)
匹配回车符(Carriage Return )
- ASCII 码值:13(十进制)或 0x0D(十六进制)
- 表示将光标移回到当前行的起始位置,不移动到下一行
- Windows/DOS:
- 使用
\r\n(CRLF, Carriage Return + Line Feed)的组合作为换行符 - 文件中的换行符显示为两个连续字符
- 使用
\t(制表符)
匹配制表符
\v(垂直制表符)
匹配垂直制表符
\f(换页符)
匹配换页符
修饰符
正则表达式修饰符(也称为模式修饰符或标记)是用于改变正则表达式匹配行为的特殊指令
i(ignore case)
忽略大小写
console.log(/abc/i.test('Abc')); // true
console.log(/abc/.test('Abc')); // false
g(global)
全局模式
- 如果能自动匹配多次的话,匹配多次(String.match、String.replace)。
- 自动变更
lastIndex。- 查找过程中遇到错误
pattern跳过继续查找。String.matchAll,String.replaceAll必须使用g
// 全局模式
const str = "hello world";
const reg = /l/;
const regByG = /l/g;
console.log(str.replace(reg, "*")); // he*lo world
console.log(str.replace(regByG, "*")); // he**o wor*d
// 自动变更lastIndex
const str = "hello world";
const reg = /l/;
const regByG = /l/g;
str.replace(reg, (match, index, input) => {
console.log(index);
return match;
});
// 2
str.replace(regByG, (match, index, input) => {
console.log(index);
return match;
});
// 2 3 9
s(single line/dotall)
单行模式
- 使点号
.匹配包括换行符(\n,\r)在内的所有字符
console.log(/a.b/s.test('a\nb')); // true
console.log(/a.b/.test('a\nb')); // false
m(multiline)
多行模式。
改变^和$的行为,使其匹配每行的开头和结尾,而不仅是整个字符串的开头和结尾。
const str = `abc\nafc\nadc`;
const reg = /^a/gm;
const newStr = str.replace(reg, "&");
console.log(newStr);
// &bc
// &fc
// &dc
const reg = /^a/g;
const newStr = str.replace(reg, "&");
// &bc
// afc
// adc
y(sticky)
粘性匹配
- 必须从正则表达式的 lastIndex 位置开始匹配,如果该位置不满足条件,则匹配失败(正则默认
lastIndex= 0)。- 用于严格的连续匹配。
// 全局匹配
const str = "abcabc";
const regexGlobal = /a./g;
console.log(regexGlobal.exec(str));
// [ 'ab', index: 0, input: 'abcabc', groups: undefined ]
console.log(regexGlobal.exec(str));
// [ 'ab', index: 3, input: 'abcabc', groups: undefined ]
console.log(regexGlobal.exec(str));
// null
// 粘性匹配
const regexSticky = /a./y;
console.log(regexSticky.exec(str));
// [ 'ab', index: 0, input: 'abcabc', groups: undefined ]
console.log(regexSticky.exec(str));
// null(因为第二次从位置2开始,字符是c,不匹配)
// 调整lastIndex继续粘性匹配
regexSticky.lastIndex = 3;
console.log(regexSticky.exec(str));
// [ 'ab', index: 3, input: 'abcabc', groups: undefined ]
粘性匹配y跟全局匹配g的区别
- 起始位置
g:只要后续位置存在匹配项,就能够继续进行匹配。y:必须从lastIndex开始
lastIndex的影响
- 当手动设置
lastIndex时,g标志会从这个设定的位置开始尝试匹配。 - 而
y标志则严格要求必须从lastIndex位置开始匹配,否则不会进行后续查找
- 匹配失败后的处理
- 若
g标志在lastIndex位置匹配失败,它会继续在后续位置寻找匹配项。 - 要是
y标志在lastIndex位置匹配失败,整个匹配过程就会终止,并且lastIndex会被重置为0。
应用场景
- 全局查找符合条件的片段
- 严格按顺序解析文本(如词法分析)
贪婪匹配&惰性匹配
正则本身是贪婪的,会尽可能多匹配符合模式的字符
贪婪量词
所有量词默认都是贪婪的
惰性量词
贪婪量词后面加
?
??:匹配 0 次或者 1 次,尽可能少匹配。*?:匹配 0 次或多次,尽可能少匹配。+?:匹配 1 次或多次,尽可能少匹配。{n,}:至少匹配 n 次,但尽可能少匹配。{n,m}: 匹配次数在 n 到 m 之间,但尽可能少匹配。
const regex = /\d{2,5}/g;
const str = '123 1234 12345 123456';
// 贪婪匹配
console.log(str.match(regex));
// [ 123, 1234, 12345, 12345 ]
// 惰性匹配
const regex2 = /\d{2,5}?/g;
console.log(str.match(regex));
// [ 12, 12, 34, 12, 34, 12, 34, 56 ]
应用:提取标签内的内容
const html = "<div>Hello</div><div>World</div>";
const regex = /<div>(.*?)<\/div>/g; // 惰性匹配
const matches = [...html.matchAll(regex)];
matches.forEach(match => console.log(match[1]));
// 输出:
// Hello
// World
const regx = /<div>(.*)<\/div>/g; // 贪婪匹配
const matches = [...html.matchAll(regex)];
matches.forEach(match => console.log(match[1]));
// 输出:
// <div>Hello</div><div>World</div>
分组引用
通过括号创建的子表达式,可以通过多种方式进行引用,大大减少表达式的复杂度
替换引用
在正则表达式的替换字符串中引用捕获组的内容,目前只有在
String.replace中使用。
使用$1、$2、${n}来引用捕获到的内容,按顺序1-n进行引用,其作用范围仅限于单次正则匹配操作,多个正则之间引用独立。
const string = '2021-08-14';
const reg = /(\d{4})-(\d{2})-(\d{2})/;
// 方法一
const result1 = string.replace(reg, '$2/$3/$1')
console.log(result1); // 输出: 08/14/2021
// 方法二
const result2 = string.replace(reg, (_,$1,$2,$3) => {
return `${$2}/${$3}/${$1}`;
});
console.log(result2); // 输出: 08/14/2021
具名引用
在正则表达式的替换字符串中引用具名捕获的内容,目前只有在
String.replace中使用。
使用$<name>来引用具名捕获内容
const str = '2023-05-15';
const newStr = str.replace(
/(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/,
'$<month>/$<day>/$<year>'
);
console.log(newStr); // "05/15/2023"
反向引用
在正则表达式内部引用之前捕获的内容。
使用\1、\2、\n来引用对应捕获组匹配的内容,确保后续匹配的内容和前面某捕获组的内容完全一样。
/*
写一个正则支持以下三种格式
2016-06-12
2016/06/12
2016.06-12
*/
const regex = /(\d{4})([-/.])\d{2}\2\d{2}/; // \2匹配表示([-/.])匹配到的内容
const string1 = "2017-06-12";
const string2 = "2017/06/12";
const string3 = "2017.06.12";
const string4 = "2016-06/12";
console.log( regex.test(string1) ); // true
console.log( regex.test(string2) ); // true
console.log( regex.test(string3) ); // true
console.log( regex.test(string4) ); // false
// 解释:([-/.])匹配-,而\2表示引用-,-跟/不匹配,
全局引用
引用全局最近一次正则实例匹配成功的内容。
使用RegExp.$1、RegExp.$2、RegExp.${n},用于存储最近一次正则匹配成功操作中的捕获组的内容,因此存在多个正则时,其值会以后者为准。
// 第一个正则匹配:捕获两个单词
const regex1 = /(\w+) (\w+)/;
regex1.exec("Hello World");
console.log(RegExp.$1); // 输出: "Hello"(第一个捕获组)
console.log(RegExp.$2); // 输出: "World"(第二个捕获组)
// 第二个正则匹配:捕获两个数字(覆盖之前的全局属性)
const regex2 = /(\d+) (\d+)/;
regex2.exec("123 456");
console.log(RegExp.$1); // 输出: "123"(第二个正则的第一个捕获组,覆盖了之前的"Hello")
console.log(RegExp.$2); // 输出: "456"(第二个正则的第二个捕获组,覆盖了之前的"World")
// 再次执行第一个正则,会重新覆盖
regex1.exec("Foo Bar");
console.log(RegExp.$1); // 输出: "Foo"(重新被第一个正则的捕获组覆盖)
注意事项
- 不推荐使用全局引用,尤其是复杂的场景下,且该特性在浏览器中非标准化。
- 反向引用如果不存在,众多资料表示在js中,不存在会报错,但实测没有报错,推荐用try catch包裹,当然也有部分引擎会解析为普通字符或者无效语句。
- 反向引用的捕获组有量词如何理解?量词只作用捕获组,而捕获组只会记录最后一次捕获的内容,如下代码:
const regex = /^(\d){2}\1c/;
console.log(regex.test("123c")); // false,最后一次捕获到的内容是2
console.log(regex.test("122c")); // true
功能分类
对支持正则的方法的功能进行分类,对这些方法返回的结果进行归纳总结,从而在面对不同问题时使用最恰当的方法,同时增加记忆。
前言
正则匹配跟
lastIndex息息相关,我们对lastIndex的认知更多停留在RegExp.lastIndex全局属性,但正则实例也有lastIndex属性
- 无
g或y:匹配的过程中,lastIndex始终为0,不可变更,修改无效,多次调用调用会得到相同的答案。 - 有
g或y修饰符:lastIndex自动变更,也支持手动变更,多次调用也就会得到不同的答案。 - 值得注意的点是当匹配失败结果为null时,
lastIndex会重置为0。
捕获组结构
const regex = /\d(\w)/; // 无 g 修饰符
const str = 'a1b2c3';
const result = regex.exec(str);
console.log(result);
// 输出:
// [
// '1b', // 匹配字符串
// 'b', // 第一个捕获组 (\w)
// index: 1, // 匹配起始位置
// input: 'a1b2c3',
// groups: undefined
// ]
// 默认捕获组内容结构(无g修饰符)
type TSingleCatchGroup = [
match: string, // 匹配字符
catch1: string, // 从1到后面都是捕获组的内容
catch2: string,
catch{n}: string
]
// 捕获组内容的方法(虽然是数组,但在js中,数组也是对象,可以给它添加自定义属性)
interface TSingleCatchGroupProp {
index: 0; // 匹配的起始位置,同lastIndex
input: string; // 原字符串
groups?: Record<string, string>; // 命名捕获组内容,详情查看具名捕获组
}
ps:这里记忆的时候,很多初学者会把index、input、groups记在数组里,其实不是。数组只有匹配项及捕获组内容,这三个属性是挂在数组下的。
验证
RegExp.test
- 检查字符是否符合具体的格式。
- 返回值类型:
boolean。 g:多次调用根据lastIndex位置,匹配失败则重置lastIndex。
const regex = /^\d{4}-\d{2}-\d{2}$/; // 验证 YYYY-MM-DD 日期格式
console.log(regex.test('2023-01-01')); // true
console.log(regex.test('2023/01/01')); // false
查找
String.search
- 类似
indexOf,但只支持正则。 - 返回值类型:
number,索引位置,从0开始,未找到返回-1 g:忽略g,只返回首个匹配位置。
const str = "hello world";
const reg = /world/;
console.log(str.search(reg)); // 6
提取
RegExp.exec
运用场景:复杂场景、需要捕获组信息的时候
- 提取匹配项、捕获组内容。
- 返回值类型:
TSingleCatchGroup g:多次调用根据lastIndex得到不同的TSingleCatchGroup
/** ---------- 不带g -------**/
const regex = /\w(\d)/;
const str = "a1b23c";
console.log(regex.exec(str));
// 输出:[ 'a1', '1', index: 0, input: 'a1b23c', groups: undefined ]
console.log(regex.exec(str));
// 输出:[ 'a1', '1', index: 0, input: 'a1b23c', groups: undefined ]
/** ---------- 带g -------**/
const regex = /\w(\d)/g;
const str = "a1b23c";
console.log(regex.exec(str));
// 输出:[ 'a1', '1', index: 0, input: 'a1b23c', groups: undefined ]
console.log(regex.exec(str));
// 输出:[ 'b2', '2', index: 2, input: 'a1b23c', groups: undefined ]
String.match
运用场景:简单场景、不需要捕获组信息,仅需匹配项
- 提取捕获项、捕获组内容。
- 返回值类型:
TSingleCatchGroup g:直接得到所有的匹配内容string[](匹配项数组,无捕获组信息)
/** ---------- 不带g -------**/
const str = "2023-05-15";
const match = str.match(/(\d{4})-(\d{2})-(\d{2})/);
console.log(match);
// 输出:[
// '2023-05-15',
// '2023',
// '05',
// '15',
// index: 0,
// input: '2023-05-15',
// groups: undefined
// ]
/** ---------- 带g -------**/
const str = 'Dates: 2023-05-15, 2024-06-16';
const matches = str.match(/(\d{4})-(\d{2})-(\d{2})/g);
console.log(matches);
// 输出:["2023-05-15", "2024-06-16"](只有匹配项,无捕获组信息)
String.matchAll
运用场景:复杂场景,且需要捕获组信息的时候
regexp必须是一个带g修饰符的正则表达式(否则会抛出错误)- 返回值类型:迭代器对象,包含所有匹配结果
TSingleCatchGrou[]
const str = 'Dates: 2023-01-01, 2024-05-15';
const regex = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/g;
// 使用 for...of 遍历迭代器
for (const match of str.matchAll(regex)) {
console.log(`
匹配位置: ${match.index}
完整日期: ${match[0]}
年: ${match.groups.year}
月: ${match.groups.month}
日: ${match.groups.day}
`);}
// 输出:
// 匹配位置: 7
// 完整日期: 2023-01-01
// 年: 2023
// 月: 01
// 日: 01
// 匹配位置: 20
// 完整日期: 2024-05-15
// 年: 2024
// 月: 05
// 日: 15
结果转数组
// 使用Array.from或者[...]等转换为数组
const str = 'Dates: 2023-01-01, 2024-05-15';
const matchList = Array.from(str.matchAll(regex));
matchList.forEach((item) => {
console.log(`
匹配位置: ${item.index}
完整日期: ${item[0]}
年: ${item.groups.year}
月: ${item.groups.month}
日: ${item.groups.day}
`);
});
替换
String.replace
运用场景:需要替换字符串
- 替换匹配成功的字符串
- 回调函数参数:
[match、catch1、catch2、...、lastIndex、input] - 返回值类型:
string g:替换所有匹配成功的字符串- 支持替换引用:
$1、$2、$n - 支持具名引用:
$<name>
// 替换引用
const str = 'John Smith';
const newStr = str.replace(/(\w+) (\w+)/, '$2, $1');
console.log(newStr); // "Smith, John"
// 具名引用
const str = '2023-05-15';
const newStr = str.replace(
/(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/,
'$<month>/$<day>/$<year>'
);
console.log(newStr); // "05/15/2023"
// 回调函数
一般使用回调的情况比较多,命名自由,灵活方便
const str = 'Today is 2023-05-15';
const newStr = str.replace(
/(\d{4})-(\d{2})-(\d{2})/,
(match, year, month, day) => `${month}/${day}/${year}`
);
console.log(newStr); // "Today is 05/15/2023"
String.replaceAll
运用场景:无需正则表达式的简单替换场景
- 直接替换所有匹配的字符串,无需正则表达式
- 如果是正则表达式,则必须带
g修饰符,否则报错(推荐使用String.replace)
// 字符串参数(无需正则)
'hello'.replaceAll('l', 'x'); // "hexxo"
// 正则参数(必须带 g)
'hello'.replaceAll(/l/g, 'x'); // "hexxo"
// 错误:正则不带 g
'hello'.replaceAll(/l/, 'x'); // TypeError
总结
- 创建方法非动态创建优先使用字面量
- 字符跟元字符改变
pattern,修饰符改变行为 g跟y的相同点在于都会变更lastIndex,不同点在于y必须连续正确匹配,而g可以跳过。对于全局匹配,只有g可以,y必须多次调用。- 横向匹配:
?、+、*、{n,m}(量词) - 纵向匹配:
[](字符组)、|(选择字符) - 惰性匹配:
?(量词后面追加) ()括号内部的元字符- 断言(位置):
?=、?!、?<=、?<! - 非捕获:
?: - 具名捕获:
?<name> - 惰性匹配:
? - 反向引用:
\1、\2
- 断言(位置):
- 特殊引用
- 正则内部:
\1、\2(反向引用) String.replace:$1、$2(替换引用)、$<name>(具名引用)
- 正则内部:
- 牢记方法
- 验证:
RegExp.test - 查找位置:
String.search - 提取内容
- 只需匹配项:
String.match - 需要捕获信息:
RegExp.exec、String.matchAll
- 只需匹配项:
- 替换内容
- 无正则:
String.replaceAll - 需要正则:
String.replace
- 无正则:
- 验证:
最后
- 有错误欢迎指正,谢谢大家。
- 运用篇可以看这位大佬写的juejin.cn/post/702167…