创建

在正则表达式中,有两种方式可以去创建正则表达式:

1. 字面量

1
const reg = /abc/;

2. 构造函数

1
const reg = new RegExp('abc');

对于这两种方式,如果正则表达式是静态的,那么,使用第一种字面量的方式,性能会比较好。但是,如果正则表达式是动态的,是根据变量来定义的,那么,只能使用第二种构造函数的方式。

语法

1. ^ 和 $的对比

^:匹配字符串的行首。示例说明:

1
2
3
4
const reg = /^A/;

console.log(reg.test('Ant')); //true
console.log(reg.test(' Ant')); //false

$:匹配字符串的行尾。示例说明:

1
2
3
4
const reg = /t$/;

console.log(reg.test('eat')); //true
console.log(reg.test('enter')); //false

2.重复限定符(*、+、?、{n}、{n,}、{n, m})

*:匹配前一个字符0次或多次,(x >= 0)

1
2
3
4
5
const reg = /a*/;

console.log(reg.test('ba')); //true
console.log(reg.test('b')); //true
console.log(reg.test('baaa')); //true

+:匹配前一个字符1次或多次,(x >= 1)

1
2
3
4
5
const reg = /a+/;

console.log(reg.test('ba')); //true
console.log(reg.test('baaa')); //true
console.log(reg.test('b')); //false

?:匹配前一个字符的0次或1次,(x = 0 || x = 1)

1
2
3
4
5
const reg = /ba?/;

console.log(reg.exec('ba')); //['ba']
console.log(reg.exec('baaa')); //['ba']
console.log(reg.exec('b')); //['b']

注:这里只是指明了?字符的限定符方面的用法,它还可以控制贪婪模式和非贪婪模式(下文可见)

{n}: 匹配前一个字符n次,(x = n)

1
2
3
4
5
const reg = /ba{3}/;

console.log(reg.test('ba')); //false
console.log(reg.test('baaa')); //true
console.log(reg.test('b')); //false

{n,}:匹配前一个字符n次或大于n次,(x >=n)

1
2
3
4
5
6
const reg = /ba{3,}/;

console.log(reg.test('ba')); //false
console.log(reg.test('baaa')); //true
console.log(reg.test('baaaa')); //true
console.log(reg.test('b')); //false

{n, m}:匹配前一个字符n次到m次之间,(n <= x <= m)

1
2
3
4
5
6
const reg = /ba{2,3}/;

console.log(reg.test('ba')); //false
console.log(reg.test('baaa')); //true
console.log(reg.test('baa')); //true
console.log(reg.test('b')); //false

3.元字符(.、\d、\w、\s、\b)

.:匹配除换行符以外的所有字符

1
2
3
4
5
6
const reg = /b.?/;

console.log(reg.exec('ba')); //['ba']
console.log(reg.exec('bxaa')); //['bx']
console.log(reg.exec('bza')); //['bz']
console.log(reg.exec('b')); //['b']

\d:匹配数字字符,与[0-9]一致(单词记忆法 => 数字【digital】)

1
2
3
4
5
6
const reg = /b\d/;

console.log(reg.exec('b1')); //['b1']
console.log(reg.exec('b2aa')); //['b2']
console.log(reg.exec('bza')); //null
console.log(reg.exec('b')); //null

\w:匹配字母、数字和下划线(单词记忆法 => 单词【word】)

1
2
3
4
5
6
const reg = /b\w/;

console.log(reg.exec('b1')); //['b1']
console.log(reg.exec('b2aa')); //['b2']
console.log(reg.exec('bza')); //['bz']
console.log(reg.exec('b')); //null

\b:匹配一个边界,一个独立单词的开头或结尾(单词记忆法 => 边界【border】)

1
2
3
4
const str = 'moon is white';

console.log(str.match(/\bm/)); //['m']
console.log(str.match(/oon\b/)); //['oon']

\s:匹配空白符(空格、换行符、制表符)(单词记忆法 => 符号【space】)

1
2
3
4
const str = 'moon is white';

console.log(str.match(/is\swhite/)); //['is white']
console.log(str.match(/moon\sis/)); // ['moon is']

4.反元字符([^x]、\D、\W、\B、\S)

[^x]:匹配除x之外的任意字符

1
2
3
4
5
const reg = /b[^a]/;

console.log(reg.exec('ba')); //null
console.log(reg.exec('bz')); //['bz']
console.log(reg.exec('by')); //['by']

\D:匹配除数字之外的任意字符,与\d相反

1
2
3
4
5
const reg = /b\D/;

console.log(reg.exec('b1')); //null
console.log(reg.exec('b2')); //null
console.log(reg.exec('by')); //['by']

\W:匹配除数字、字母和下划线以外的任意字符,与\w相反

1
2
3
4
5
6
const reg = /b\W/;

console.log(reg.exec('b1')); //null
console.log(reg.exec('ba')); //null
console.log(reg.exec('b_')); //null
console.log(reg.exec('b*')); //['b*']

\B:匹配非单词边界的字符,与\b相反

1
2
3
4
const str = 'moon is white';

console.log(str.match(/\Boon/)); //['oon']
console.log(str.match(/whit\B/)); //['whit']

\S:匹配非空白字符,与\s相反

1
2
3
4
const str = 'moon is white';

console.log(str.match(/mo\Sn/)); //['moon']
console.log(str.match(/whit\S/)); //['white']

5.字符组([…])

[…]:匹配方括号中的字符集合,例如[0-9] => 匹配数字字符

1
2
3
4
const reg = /b[a-z]/;

console.log(reg.test('ba')); //true
console.log(reg.test('bA')); //false

6.分组((…))

(X):将括号中的字符看成一个组进行匹配,例如(ab)+ => 可以匹配’ababab’

1
2
3
4
const reg = /(abab)+/;

console.log(reg.exec('ababab')); //['abab', 'abab']
console.log(reg.exec('abababab')); //['abababab','abab']

(?:X):匹配X,但是不记录匹配项。而上面的(X)是记录匹配项的。
(?=X):正向肯定查找,即匹配后面紧跟X的字符串。

1
2
3
const reg = /\d+(?=\.)/;

console.log(reg.exec('3.141')) //['3']

(?!X):正向否定查找,即匹配后面不跟X的字符串,与(?:X)相反。

1
2
3
const reg = /\d+(?!\.)/;

console.log(reg.exec('3.141')) //['141']

7.多选符 (|)

|:匹配两者中的一个,例如a|b => 匹配a或b

1
2
3
4
5
const reg = /a|b/;

console.log(reg.exec('a')); //['a']
console.log(reg.exec('b')); //['b']
console.log(reg.exec('c')); //['c']

8.转移字符(\)

\:表示转义字符,将特殊的字符转义成普通字符进行匹配

匹配方式

匹配方式,即正则表达式在匹配过程中,当具备多个结果时,按照一定的模式进行匹配。
匹配方式可分为两种,贪婪模式和非贪婪模式。
贪婪模式:即以限定符最大重复标准进行匹配。例如:使用/ba/匹配’baaaaa’时,结果可返回’baaaaa’
非贪婪模式:即以限定符最小重复标准进行匹配。例如:使用/ba
?/匹配’baaaaa’时,结果可返回’b’

1
2
3
4
const str = 'baaaaa';

console.log(str.match(/ba*/)); //['baaaaa']
console.log(str.match(/ba*?/)); //['b']

其中?符号起到了贪婪与非贪婪模式之间的转变,在重复限定符后加上?,按非贪婪模式进行匹配;默认为贪婪模式。

标识方式

标识方式,就是正则表达式后面跟的匹配方式,flag
g:全局匹配,记忆方式【global】
i:忽略大小写,记忆方式【ignore】
m:多行搜索,记忆方式【multline】
u: 用来处理4字节的UTF-16编码字符【unicode】
y: 与g类似,也是全局匹配。但y确保匹配必须从剩余的第一个位置开始【sticky】
这里对m、u和y分别举一个栗子:**m:

1
2
const aaa='@123\n@234\n@345';
aaa.replace(/^@\d/gm,'Q'); // 如果不加m则只有"@1"会被替换

u:
ES 6的字符串扩展中新增了使用大括号表示 Unicode 字符,如果使用这种表示法,那么在正则表达式中必须加上u修饰符,才能识别其中的大括号,否则{}会被解读为量词:

1
2
3
/\u{61}/.test('a'); // false,表示必须要匹配61个u字符
/\u{61}/u.test('a'); // true
/\u{20BB7}/u.test('𠮷'); // true

y:
y与g一样都是全局匹配,但g只要剩余串中存在匹配就可,而y修饰符确保匹配必须从剩余的第一个位置开始匹配,这也就是“粘连(sticky)”的涵义:

1
2
3
4
5
var s = 'aaa_aa_a';
var r1 = /a+/g;
var r2 = /a+/y;
s.replace(r1, 'X'); // "X_X_X"
s.replace(r2, 'X'); //"X_aa_a"

如何检测正则表达式使用了u或y修饰符呢?
ES 6新增了unicode和sticky属性分别来检测:

1
2
3
4
var r2 = /\u{61}/u;
r2.unicode; // true
var r = /a+/y;
r.sticky; // true

另外ES 6还新增了flags属性用来查看正则表达式使用了哪些修饰符:

1
2
var r2 = /\u{61}/ugimy;
r2.flags; // "gimuy"

方法

使用正则表达式的方式一共有6种,可以分成:reg有两种,string有四种。
首先,我们来看一下reg对象带的两种方法:exec和test

1. test => 判断字符串中是否存在与正则表达式匹配的字符串,返回boolean类型

1
2
3
4
const reg = /abc/;

console.log(reg.test('abca')); //true
console.log(reg.test('abac')); //false

2. exec => 匹配字符串中满足条件的字符串,返回一个匹配的结果数组

1
2
3
const reg = /\d+/;

console.log(reg.exec('1234dhi343sf2')); //['1234']

之后是string的四种方法:match、search、replace、split

3.match:查找字符串中的匹配的字符串,返回一个结果数组,若没有匹配则返回null

1
2
3
const str = 'this is reg expression test'

console.log(str.match(/\bi.\s\w+/)); //['is reg']

4. search:查找字符串中匹配的字符串,返回匹配字符串的下标,若没有匹配则返回-1

1
2
3
const str = 'this is reg expression test'

console.log(str.search(/\bi.\s\w+/)); //5

5.replace:查找字符串中匹配的字符串,对其进行替换(这是一个个人觉得比较厉害的技能)

  • 接收字符串
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    const str = 'this is reg expression test'

    console.log(str.replace(/\b(i.)\s(\w+)/, '$1 hello $2')); //'this is hello reg expression test'

    接收函数
    const str = 'this is reg expression test'

    str.replace(/\b(i.)\s(\w+)/, (...args) => {
    console.log(args);
    }); //["is reg", "is", "reg", 5, "this is reg expression test"]

注:这个函数会有一些参数,第一个是匹配的字符串,第二个是第一项匹配的,第三个是第二项匹配的,第四个是匹配的下标,第五个是原字符串

6.split:使用正则表达式或者固定字符,分割字符串

1
2
3
const str = 'this is reg expression test'

console.log(str.split(/\s/)) //["this", "is", "reg", "expression", "test"]

应用

1、匹配中文

1
2
3
const str='只能是中文';
const reg=/^[\u4E00-\u9FFF]+$/;
console.log(reg.test(str));

2、匹配双字节字符(包括汉字)

1
2
3
const str='匹配双字节字符';
const reg=/[^\x00-\xff]/;
console.log(reg.test(str));

3、手机号码严格版,验证前3位

1
2
3
const str='15000000000';
const reg=/^(13[0-9]|17[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|16[4]|18[0-9])\d{8}$/;
console.log(reg.test(str));

4、手机号码验证前两位(注:现在有13、14、15、17、18开头的)

1
2
3
const str='15000000000';
const reg=/^1[34578]\d{9}$/;
console.log(reg.test(str));

5、IP地址

1
2
3
const str='20.20.26.20';
const reg=/^((2[0-4]\d|25[0-5]|1\d{2}|[1-9]?\d)\.){3}(2[0-4]\d|25[0-5]|1\d{2}|[1-9]?\d)$/;
console.log(reg.test(str));

6、邮箱

1
2
3
const str='123@163.com';
const reg=/[\w!#$%&'*+/=?^_`{|}~-]+(?:\.[\w!#$%&'*+/=?^_`{|}~-]+)*@(?:[\w](?:[\w-]*[\w])?\.)+[\w](?:[\w-]*[\w])?/;
console.log(reg.test(str));

7、匹配URL

1
2
3
const str='http://www.imooc.com';
const reg=/[a-zA-z]+://[^\s]*/;
console.log(reg.test(str));

8、匹配国内电话号码

1
2
3
const str='0531-88881234';
const reg=/\d{3}-\d{8}|\d{4}-\{7,8}/;
console.log(reg.test(str));

9、匹配腾讯QQ号

1
2
3
const str='88881234';
const reg=/[1-9][0-9]{4,}/;
console.log(reg.test(str));

10、匹配中国邮政编码

1
2
3
const str='881234';
const reg=/[1-9]\d{5}(?!\d)/;
console.log(reg.test(str));

11、匹配18位身份证

1
2
3
const str='123456789012345678';
const reg=/^(\d{6})(\d{4})(\d{2})(\d{2})(\d{3})([0-9]|X)$/;
console.log(reg.test(str));

12、匹配年-月-日格式日期

1
2
3
const str='1991-07-10';
const reg=/([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3})-(((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01]))|((0[469]|11)-(0[1-9]|[12][0-9]|30))|(02-(0[1-9]|[1][0-9]|2[0-8])))/;
console.log(reg.test(str));

13、匹配整数

1
2
3
const str='12';
const reg=/^(-|\+)?[1-9]\d*$/;
console.log(reg.test(str));

14、匹配小数

1
2
3
const str='12.99';
const reg=/^(-|\+)?[1-9]\d*\.\d*|-0\.\d*[1-9]\d*$/;
console.log(reg.test(str));

相关面试题

1、请用js去除字符串空格?

str为要去除空格的字符串,实例如下:

1
const str = "   xiao  ming   ";

使用replace正则匹配的方法
去除所有空格: str = str.replace(/\s/g,””);
去除两头空格: str = str.replace(/^\s
|\s$/g,””);
去除左空格: str = str.replace( /^\s
/, “”);
去除右空格: str = str.replace(/(\s*$)/g, “”);