正则对象 RegExp.prototype
每次遇到 /regexp/
或 new RegExp(regexp)
都会重新创建正则表达式对象
- 把正则表达式保存在变量中复用则不会重新创建
JavaScript 中的正则表达式对象是有状态的,其lastIndex
属性用来保存 在字符串中进行下次匹配的偏移值。
每次匹配(执行
exec()
和test()
)都会更新lastIndex
的值- 匹配成功,更新到匹配文本的下一个字符位置
- 匹配失败,更新为0
更换查找的字符串,不改变正则对象的
lastIndex
属性值while循环条件中使用正则表达式对象
非复用正则对象,每次循环都会创建新的正则对象,lastIndex 属性值为0,如果匹配成功,将造成死循环
复用正则对象,没有指定
/g
模式,如果匹配成功,lastIndex 属性重置为0,将造成死循环如果指定
/g
模式,匹配成功将更新 lastIndex 属性值,直到字符串末尾,匹配结束,循环结束,不会造成死循环
exec
对指定字符串执行搜索匹配。返回一个结果数组或 null
语法
1 | regexObj.exec(str) |
如果匹配成功,返回一个数组, 并更新 regexObj 对象的
lastIndex
属性值索引 描述 [0] 整体匹配的文本(整个正则表达式匹配的文本) [1],…[n] 分组捕获的内容(如果没有分组,则没有这一项) index 整体匹配的文本的第一个字符在原始字符串中基于0的索引值 input 原始字符串 groups 具名捕获时,用于存储匹配文本的对象. 默认为 undefined, 只有采用具名捕获时才有值 如果匹配失败,返回 null,并将
lastIndex
重置为 01
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
29const regexp2 = /([a-z]+)#([A-Z]+)#(\d{4})/; // 复用正则表达式对象
const str2 = 'lazada#MY#5474 amazon#VN#1234';
// =============分组捕获==============
console.log('exec2 = ', regexp2.exec(str2), regexp2.lastIndex);
console.log('exec3 = ', regexp2.exec(str2), regexp2.lastIndex); // 遍历第二个
// 输出
exec2 = [
'lazada#MY#5474', // 整个正则表达式匹配的文本
'lazada', // 分组匹配的内容
'MY', // 分组匹配的内容
'5474', // 分组匹配的内容
index: 0, // 整个正则表达式匹配的文本的第一个字符在原始字符串中的索引
input: 'lazada#MY#5474 amazon#VN#1234', // 原始字符串
groups: undefined
] 0
exec3 = [ // 未加 g 标志时, 多次执行的结果相同
'lazada#MY#5474',
'lazada',
'MY',
'5474',
index: 0,
input: 'lazada#MY#5474 amazon#VN#1234',
groups: undefined
] 0
// =============未分组捕获==============
> /[^a-c]+/.exec('bike');
[ 'ike', index: 1, input: 'bike', groups: undefined ]如果使用
g
标志,匹配成功后,会更新lastIndex
属性。使用此特性,可多次执行exec
方法来查找同一个字符串中的多个匹配项1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18exec2 = [
'lazada#MY#5474',
'lazada',
'MY',
'5474',
index: 0,
input: 'lazada#MY#5474 amazon#VN#1234',
groups: undefined
] 14 // 记录 lastIndex
exec3 = [ // 多次执行,结果不同
'amazon#VN#1234',
'amazon',
'VN',
'1234',
index: 15,
input: 'lazada#MY#5474 amazon#VN#1234',
groups: undefined
] 29
test
- 检测指定字符串是否匹配正则表达式
语法
1 | regexObj.test(str) |
返回值
类型:布尔
true
字符串与正则表达式匹配
false
不匹配
通过
RegExp.$1~RegExp.$9
:获取本次正则匹配后,第一个到第九个分组的信息(不常用)没有 RegExp.$0
1 | let str = "{0}年{1}月{2}日"; |
字符串 String.prototype
search
检测字符串是否匹配正则表达式
寻找正则表达式在字符串中第一次匹配成功的位置。如果匹配失败,则返回
-1
全局模式
/g
不影响返回结果
语法
1 | str.search(regexp) |
返回值
类型:Number
匹配成功则返回首次匹配文本的索引
索引从0开始,匹配文本的第一个字符的索引
匹配失败则返回
-1
replace
- 替换字符串中的指定部分,返回一个新字符串(不改变原字符串)
- 默认只进行一次替换
语法
1 | str.replace(regexp|substr, replacement|function) |
regexp
一个 RegExp 对象或者其字面量。该正则所匹配的内容会被第二个参数替换掉
substr
字符串,指定原字符串中被替换的部分
- 仅第一个匹配项会被替换
- 每次匹配都从字符串第一个字符开始
replacement
替换字符串,用于替换第一个参数在原字符串中匹配到的结果
替换字符串中可以使用的特殊变量名
变量名 描述 $$ 插入一个’$’字符 $& 插入匹配的子串 $` 插入当前匹配子串左侧的所有字符 $’(英文单引号) 插入当前匹配子串右侧的所有字符 $n 插入对应捕获分组匹配的子串,索引从1开始,如果没有对应的分组,则替换为字面量( ‘$3’) $<name> 插入命名分组捕获的子串,如果不存在命名分组则替换为字面量,如果存在但引用名称错误则替换为空串 1
2
3
4
5
6
7> 'the price is 12.99 dollar'.replace(/(\d+\.\d{0,2})/u,"$$ $0 $1 $`$' $& $<age>");
'the price is $ $0 12.99 the price is dollar 12.99 $<age> dollar'
>
> 'the price is 12.99 dollar'.replace(/(?<num>\d+\.\d{0,2})/u,"$$ $0 $1 $`$' $& $<num>");
'the price is $ $0 12.99 the price is dollar 12.99 12.99 dollar'
> 'the price is 12.99 dollar'.replace(/(?<num>\d+\.\d{0,2})/u,"$$ $0 $1 $`$' $& $<num> $<sum>");
'the price is $ $0 12.99 the price is dollar 12.99 12.99 dollar' #替换为空串function
回调函数,返回一个字符串,替换第一个参数匹配到的子串
用正则
reg
跟字符串str
进行匹配,获取匹配内容(字符串数组,跟exec
捕获的结果一致)执行回调函数,并把捕获到的内容以字符串列表的形式传递给回调函数
参数名 描述 match 整个正则匹配的结果 p1,p2…pn 分组捕获的结果 offset 整个正则匹配的结果的第一个字符在原字符串中的索引 string 原字符串 1
2
3
4
5
6
7
8
9function replacer(match, p1, p2, p3, offset, string) {
console.log(match, p1, p2, p3, offset, string);
// c12345#$*% c 12345 #$*% 3 ab6c12345#$*%111
return [p3, p2, p1].join('-');
}
// 整个正则作为一个整体去匹配,而不是每个组单独匹配。
// 做为一个整体匹配后,再分组捕获
var newString = 'ab6c12345#$*%111'.replace(/([^\d]*)(\d*)([^\w]+)/, replacer);
console.log(newString); // ab6#$*%-12345-c111用回调函数的返回结果替换第一个参数匹配到的结果
每匹配一项,上面的3步就执行一次。替换之后再去匹配下一项
功能强大,真实项目中推荐使用
示例
第一个参数为字符串
每次匹配都从字符串第一个字符开始,且只能替换一个匹配项(类似正则的懒惰性)
基于正则
g
修饰符解决replace
的“懒惰性”1
2
3
4
5
6
7
8let str = "zhufeng@2019|zhufeng@2020";
//=>把"zhufeng"替换成"珠峰"
str = str.replace("zhufeng","珠峰").replace("zhufeng","珠峰");
console.log(str);
//2.使用正则会简单一点
str = str.replace(/zhufeng/g,"珠峰");
console.log(str);
第一个参数为正则
处理时间字符串
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23let time = "2019-08-13";
//=>变为"2019年08月13日"
let reg = /^(\d{4})-(\d{1,2})-(\d{1,2})$/;
//方式一:通过 $1~9 获取小分组匹配捕获到的内容
time = time.replace(reg,"$1年$2月$3日");
console.log(time); //=>2019年08月13日
// 方式二:底层原理
time = time.replace(reg, (big, $1, $2, $3) => {
//=>这里的$1~$3是我们自己设置的变量
console.log(big, $1, $2, $3);
});
time = time.replace(reg, (...args) => {
// 不接收第一项大正则捕获的内容,空出来(用逗号隔开)
// 解构赋值
let [, $1, $2, $3] = args
$2.length < 2 ? $2 = "0" + $2 : null;
$3.length < 2 ? $3 = "0" + $3 : null;
return $1 + "年" + $2 + "月" + $3 + "日";
})单词首字母大写
- 大正则捕获每个单词
- 小分组捕获单词的首字母
1
2
3
4
5
6
7
8
9
10
11
12
13
14let str = "good good study,day day up!"
// 要获取首字母,则第一个小正则用小括号包起来
let reg = /\b([a-zA-Z])[a-zA-Z]*\b/g;
//=>函数被执行了六次,每一次都把正则匹配信息传递给函数,arg:["good","g"] ["good","g"] ["study","s"]...
str = str.replace(reg, (...arg) => {
let [content, $1] = arg;
// 首字母大写
$1 = $1.toUpperCase();
// 获取单词除首字母之外的字符串
content = content.substring(1);
// 返回拼接后的字符串
return $1 + content;
});
console.log(str); //=>"Good Good Study,Day Day Up!"
match
- 捕获与正则表达式匹配的结果,返回一个结果数组或 null
语法
1 | str.match(regexp) |
正则表达式
/g
模式返回一个字符串数组,包含与大正则(整个正则表达式)匹配的结果,但不包含分组捕获的结果
正则表达式不加
/g
模式返回与大正则(整个正则表达式)匹配的结果,及分组捕获的结果,及相关属性
属性 描述 [0] 大正则(完整正则表达式)匹配的结果 [1],[2],…[n] 分组捕获的结果 index 大正则(完整正则表达式)匹配结果的第一个字符的索引 input 原字符串 groups 一个捕获组数组 或 undefined(未定义命名捕获组) 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15> '#ax'.match(/#(?<site>[A-Z]*)/)
[
'#',
'',
index: 0,
input: '#ax',
groups: [Object: null prototype] { site: '' }
]
> '#ax'.match(/#(?<site>[A-Z]*)/).groups.site
''
>
> '#ax'.match(/#([A-Z]*)/)
[ '#', '', index: 0, input: '#ax', groups: undefined ]
> '#ax'.match(/#([A-Z]*)/).groups.site
Uncaught TypeError: Cannot read property 'site' of undefined1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21var str = 'hi see Chapter 3.4.5.1';
var re = /see (chapter \d+(\.\d)*)/i;
var found = str.match(re);
console.log(found);
// [
// 'see Chapter 3.4.5.1',
// 'Chapter 3.4.5.1',
// '.1', // 捕获了3次,在保存最后一次的结果
// index: 3,
// input: 'hi see Chapter 3.4.5.1',
// groups: undefined
// ]
var re = /see (chapter \d+(\.\d)*)/gi;
var found = str.match(re);
console.log(found);
// [ 'see Chapter 3.4.5.1' ]
split
使用指定的分隔符分割字符串,返回一个字符串数组
语法
1 | str.split(separator [, limit]) |
separator 可以是正则表达式
如果正则表达式包含捕获分组,则捕获文本会被拼接到返回数组中
1
2
3
4
5> 'one1two2three'.split(/\d/u,3)
[ 'one', 'two', 'three' ]
>
> 'one1two2three'.split(/(\d)/u,3)
[ 'one', '1', 'two' ]