JavaScript 正则表达式

一、概念

正则表达式是用于匹配字符串中字符组合的模式。

1
2
3
4
var expression = / pattern / flag;

// pattern:一个字符串,指定了正则表达式的模式或其他正则表达式。
// flag:1)g:全局模式;2)i:不区分大小写模式;3)m:多行模式

二、种类

1、简单字符

字符本身

1
/hello/g

2、方括号

[]指代一个字符,里面的字符表示这个字符的选择范围

1)范围类

-表示一个范围内的字符

1
[0-9] <=> [0123456789]

2)组合类

范围类的组合

1
2
[0-9a-fA-F] // 十六进制 
// 组合之间不能用空格

3)负向类

表示不在方括号之间的任何字符

1
[^0-9]

3、量词

表示前面字符出现的次数。

贪婪量词: 找到匹配的最大串,找到最后才停止

惰性量词: 找到匹配的最小串,找到就停止

贪婪量词 惰性量词 描述
{0, 1} 或 ? ?? 至少 0 次,至多 1 次
{0, } 或 * *? 至少 0 次
{1, } 或 + +? 至少 1 次
{n} {n}? 出现n次
{n, m} {m, n}? 至少 n 次,至多 m 次
{n, } {m, }? 至少 n 次,至多不限
1
/[0-9]{4}/g

4、通配符

类别 描述
. [^\n\r],除了回车换行以外,都可以匹配。
\d [0-9],数字
\D [^0-9],非数字
\w [a-zA-Z_0-9],数字字母下划线
\W [^a-zA-Z_0-9],非数字字母下划线
\s [\t\n\x0B\f\r],空格或者空白
\S 非空格或者非空白
\b 表示边界(两个字符中间的位置)一边是\w,另一边是\W
\B 不是边界
^ 表示开始
$ 表示结束

5、分组

一个正则表达式,不但可以对整个匹配进行操作,还可以对其中()中的子串进行匹配,即分组。

1)(pattern) 匹配 pattern 同时捕获结果,自动设定好组。

1
2
\1
RegExp.$1 // 反向引用

2)(?\pattern) 匹配 pattern 同时捕获结果,设定 name 为组名。

1
\k\<name> // 反向引用

例:

1
2
3
4
5
6
7
var str = 'word excel excel hello world world!';

str.match(/(\b[a-zA-Z]+\b)\s+\1/g); // ["excel excel", "world world"]

str.match(/(?<n1>\b[a-zA-Z]+\b)\s+\k<n1>/);

RegExp.$1; // "excel"

6、零宽(负向)先行\后行断言

开头是:(?<=什么) 开头不是:(?<!=什么)

结尾是:(?=什么) 结尾不是:(?!=什么)

1
2
3
4
5
6
7
8
9
10
11
12
13
str = 'r;e;a;a;a;rcaaa=bbb=;';

// 寻找两个字符,两字符后面以分号结尾
str.match(/.{2}(?=;)/g);

// 寻找四个字符,以ea开头
str.match(/(?<=ea).{4}/g);

// 寻找三个字母,不以分号结尾
str.match(/[a-z]{3}(?!;)/g);

// 寻找不易re开头的三个字母
str.match(/(?<!re)a{3}/);

7、|(或)

1
2
3
str = 'var    	aaadf1;';
str2 = 'function f(){}';
str.match(/^var\s+[a-zA-Z]\w*;|^function\s+[a-zA-Z]\w*\s*\(\)\{\}/);

三、创建方式

1、正则表达式字面量

1
var pattern = /[bc]at/i;

2、正则表达式类 RegExp

1
2
var pattern = new RegExp("[bc]at", "i");
// 注意双重转义

正则表达式字面量始终共享同一个 RegExp 实例,构造函数创建的每一个新的 RegExp 实例都是一个新实例。

RegExp 构造函数上有一些属性,并且这些属性跟着执行的最后一次正则表达式操作而变化。

1
2
3
4
5
6
7
8
9
10
var text = 'this has been a short summer';
var pattern = /(.)hort/g;
if (pattern.test(text)) {
console.log(RegExp.input); // this has been a short summer
console.log(RegExp.leftContext); // this has been a
console.log(RegExp.rightContext); // summer
console.log(RegExp.lastMatch); // short
console.log(RegExp.lastParen); // s
console.log(RegExp.multiline); // false
}

RegExp.\$1,…RegExp.$9,存储捕获的组。

1)RegExp 实例属性

通过 global、ignoreCase、multiline、lastIndex、source 这几个属性获取一个正则表达式相关的信息。

四、使用

1、RegExp 实例方法

1)test(string)

表示当前正则是否匹配指定的字符串,返回布尔值。

1
2
3
4
5
var regExp = new RegExp('[0-9]+','g');  
// 或
var regExp2 = /[0-9]+/g; // 有g,匹配所有的字符串;没有g,匹配完第一个然后停止。
var str = 123;
console.log(regExp2.test(str)); //true

在指向知道目标字符串和某个模式是否匹配,但不需要知道其文本内容的情况下使用。

2)exce(string)

表示当前正则是否匹配指定的字符串,返回匹配的数组(找不到返回null)

备注:该方法是为捕获组而专门设计的,该方法接收应用模式的字符串,返回一个数组且额外带有index,input属性。index 表示匹配项在字符串中的位置;input 是应用正则表达式的字符串。且数组第一项是和模式匹配的整个字符串;其他项是和模式中捕获的组匹配的字符串。

1
2
3
4
5
6
7
8
9
var test = "mom and dad and baby";
var pattern = /mom( and dad( and baby)?)?/gi;

var matches = pattern.exec(test);
console.log(matches[0]) // "mom and dad and baby"
console.log(matches[1]) // " and dad and baby"
console.log(matches[2]) // " and baby"
console.log(matches.index) // 0
console.log(matches.input) // "mom and dad and baby"
  • 模式中设置 g:在同一字符串上多次调用 exec() 始终返回第一个匹配项的信息。

  • 模式中不设置 g:在同一字符串上多次调用 exec() 会在字符串中继续查找新的匹配项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var text = 'cat, bat, sat, fat';
var pattern1 = /.at/;

var matches = pattern1.exec(text);
console.log(matches.index); // 0
console.log(matches[0]); //cat
console.log(pattern1.lastIndex); // 0

matches = pattern1.exec(text);
console.log(matches.index); // 0
console.log(matches[0]); //cat
console.log(pattern1.lastIndex); // 0

var pattern2 = /.at/gi
var matches1 = pattern2.exec(text);
console.log(matches1.index); // 0
console.log(matches1[0]); //cat
console.log(pattern2.lastIndex); // 3
// 可被用于循环匹配统计字符串中字符出现的次数

2、String 支持的正则函数

1)match(regexp):返回数组

1
str.match(/[0-9]+/g);

没有g,第一个匹配的最大串,其他是分组的子串,index:最大串开始的位置, input原始的串

有g,返回数组,所有匹配的最大串,但是没有分组的子串,index和input无效。

2)replace(regexp/substr, replacement):返回字符串

regexp 表示正则表达式。

substr表示子串。

replacement 表示替换进去的串,或者函数。\$1 ~ $99 分组,\$&代表子串; \$` 子串左侧; \$’ 子串右侧。

1
2
3
4
5
// 把小写的 word 变成大写的 WORD
str = 'word'
str.replace(/\bword\b/, 'WORD');
str.replace(/\bword\b/g, 'WORD');
str.replace('word', 'WORD');
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
// 匹配 单词1-单词2 模式,然后变成单词2-单词1
str = 'aaaa-bbbb@cc-ddd';
console.log(str.replace(/([a-z]+)-([a-z]+)/g, replacer));

// 函数的第一项是匹配的内容。
// 接下来的参数是与模式中的子表达式匹配的字符串,可以有 0 个或多个这样的参数。
// 接下来的参数是一个整数,声明了匹配在 stringObject 中出现的位置。
// 最后一个参数是 stringObject 本身。
function replacer(match, p1, p2, offset, str){
//console.log(match, p1, p2, offset, str);
var sRet = '';
for(var i = 0; i < p2.length; i++){
sRet += String.fromCharCode(p2.charCodeAt(i) + 1);
}
sRet += '=';
for(var i = 0; i < p1.length; i++){
sRet += String.fromCharCode(p1.charCodeAt(i) + 1);
}
return sRet;
}

// 结果
// aaaa-bbbb aaaa bbbb 0 aaaa-bbbb@cc-ddd
// cc-ddd cc ddd 10 aaaa-bbbb@cc-ddd
// cccc=bbbb@eee=dd

3)search(regExp)

直接量和对象,返回整数,开始的位置,-1表示没有找到。

1
2
3
str = 'I word site excel word OK chrome match OK excel word';
//找word
console.log(str.search(/\bword\b/));

注意:search 不支持全局,忽略参数 g,同时忽略 regexp 的 lastIndex

4)split(separator, howmany)

把一个字符串分隔成数组。separator 正则,字符串,可选;howmany 是最大长度。

1
2
var str = 'a,b.c'
str.split(/,|\./) // [a, b, c]

五、练习

1、如何将浮点数点左边的数每三位添加一个逗号,如 12005009.11 转化为 12,005,009.11

1
2
3
4
5
6
7
function commafy(num) {
return (
num && num.toString().replace(/(\d)(?=(\d{3})+\.)/g, function (match, $1) {
return $1 + ",";
})
);
}
微信打赏