Skip to main content

JS 正则表达式

正则表达式(Regular Expression)使用单个字符串来描述、匹配一系列符合某个句法规则的字符串搜索模式,是用于匹配字符串中字符组合的模式。

「点击查看正则表达式对象 RegExp 的属性和方法」

一、JS 如何创建正则表达式

1、隐式创建

通过字面量 / 定义:

var str = 'I love Leophen';
var pattern = /Leophen/;
// test exec
console.log(pattern.test(str)); // true
console.log(pattern.exec(str)); // "Leophen"

2、显式创建

通过构造函数 new RegExp() 定义:

var str = 'I love Leophen';
var pattern = new RegExp('Leophen');
console.log(pattern.test(str)); // true
console.log(pattern.exec(str)); // "Leophen"

二、正则表达式特殊字符

1、任意字符 .

. 即通配符,表示任何单个字符(换行符、回车符除外)。

  • 示例:/.n/ 将会匹配 "nay, an apple is on the tree" 中的 'an''on',但是不会匹配 'nay'

2、指定的任意字符 [...]

[...] 一个字符集合,匹配方括号中的任意字符,可以用破折号(-)来指定一个字符范围。

  • 示例:[abcd][a-d] 一样,都匹配 "brisket" 中的 ‘b’,也都匹配 “city” 中的 ‘c’
// 字面量(这里举汉字的示例)
var pattern = /[\u4e00-\u9fa5]/;
// 构造函数
var pattern = new RegExp('[\u4e00-\u9fa5]');

3、除了指定的任意字符 [^...]

[^...] 一个反向字符集,匹配不在方括号内的任意字符,可以使用破折号(-)来指定一个字符范围。

  • 示例:[^abc][^a-c] 一样,都匹配 "brisket" 中的 ‘r’,也都匹配 “chop” 中的 ‘h’

4、a-z 中任意字符 [a-z]

[a-z] 表示小写字符中的任何一个字符。

5、除了 a-z 的任意字符 [^a-z]

[^a-z] 表示除了小写字符中的任何一个字符。

6、任意单字字符 ╲w

\w 表示数字、大小写字母和下划线,等价于 [a-zA-Z0-9_]

  • 示例:/\w/ 匹配 "apple," 中的 'a'"$5.28," 中的 '5'"3D." 中的 '3'

7、除了任意单字字符 ╲W

\W 表示除了数字、大小写字母和下划线,等价于 [^a-zA-Z0-9_]

  • 示例:/\W/ 匹配 "50%." 中的 '%'

8、任意数字 ╲d

\d 表示任意数字,等价于 [0-9]

  • 示例:/\d/ 匹配 "B2 is the suite number." 中的 '2'

9、除了任意数字 ╲D

\D 表示除数字外的任意字符,等价于 [^0-9]

  • 示例:/\D/ 匹配 "B2 is the suite number." 中的 'B'

8、任意空白字符 ╲s

\s 表示一个空白字符,包括空格、制表符、换页符和换行符。等价于[ \f\n\r\t\v\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]

  • 示例:/\s\w*/ 匹配 "foo bar." 中的 ' bar'

9、任意非空白符 ╲S

\S 表示一个非空白字符,与 \w 不一样,等价于 [^ \f\n\r\t\v\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]

  • 示例:/\S\w*/ 匹配 "foo bar." 中的 'foo'

10、其它更多字符

10-1、NULL 字符 ╲o

\o 表示 NULL(U+0000)字符,不要在这后面跟其它小数,因为 \0<digits> 是一个八进制转义序列。

10-2、水平制表符 Tab ╲t

\t 表示一个水平制表符 (U+0009)。

10-3、垂直制表符 ╲v

\v 表示一个垂直制表符 (U+000B)。

10-4、换行符 ╲n

\n 表示一个换行符 (U+000A)。

10-5、回车符 ╲r

\r 表示一个回车符 (U+000D)。

10-6、换页符 ╲f

\f 表示一个换页符 (U+000C)。

10-7、两位 16 进制数字符 ╲xhh

\xhh 表示一个两位十六进制数(\x00-\xFF)表示的字符。

10-8、四位 16 进制数字符 ╲uhhhh

\uhhhh 表示一个四位十六进制数表示的 UTF-16 代码单元。

10-9、控制字符 ╲cX

\cX 表示当 X 是处于 A-Z 之间的字符时,匹配字符串中的一个控制符。

  • 示例:/\cM/ 匹配字符串中的 control-M (U+000D)

10-10、退格直接量(特例)

[\b] 表示一个退格(U+0008)。注意不要和匹配边界的 \b 混淆。

三、正则表达式修饰符

1、全局匹配 g

g(global)表示执行全局匹配即查找所有匹配而非在找到第一个匹配后停止。

示例:

var str = 'I love Leophen';
var pattern = /o/g;

console.log(str.replace(pattern, 'x')); // I lxve Lexphen

2、忽略大小写 i

i(ignoreCase)表示执行对大小写不敏感的匹配。

示例:

var str = 'Leophen';
var pattern = new RegExp('l', 'i');

console.log(str.replace(pattern, 'D')); // Deophen

3、多行匹配 m

m(multiline)表示执行多行匹配。

示例:

var str = `s1 place: Winnie
s2 place: Tim
s3 place: Bang`;

var pattern1 = /^s/g;
var pattern2 = /^s/gm;

console.log(str.replace(pattern1, 'x'));
// x1 place: Winnie
// s2 place: Tim
// s3 place: Bang

console.log(str.replace(pattern2, 'x'));
// x1 place: Winnie
// x2 place: Tim
// x3 place: Bang

4、兼容 Unicode 模式 u

u(unicode)表示 Unicode 模式,用来正确处理大于 \uFFFF 的 Unicode 字符,也就是说能够正确处理 UTF-16 编码。

示例:

var str = '☺';

var pattern1 = /\p{Emoji}/;
var pattern2 = /\p{Emoji}/u;

console.log(str.replace(pattern1, 'x')); // ☺
console.log(str.replace(pattern2, 'x')); // x

5、执行粘性搜索 y

y(sticky)表示搜索是否具有粘性。

示例:

var str = "applewatch";

var pattern1 = /a/g;
console.log(pattern1.exec(str)); // ['a'] index:0
console.log(pattern1.exec(str)); // ['a'] index:6
console.log(pattern1.exec(str)); // null

var pattern2 = /a/y;
console.log(pattern2.exec(str)); // ['a'] index:0
console.log(pattern2.exec(str)); // null

四、正则表达式断言/锚字符

1、匹配开头 ^

^ 用来匹配字符串的开头,在多行检索中,匹配每一行的开头。

示例:

var str = `s1 place: Winnie
s2 place: Tim
s3 place: Bang`;

var pattern1 = /^s/g;
var pattern2 = /^s/gm;

console.log(str.replace(pattern1, 'x'));
// x1 place: Winnie
// s2 place: Tim
// s3 place: Bang

console.log(str.replace(pattern2, 'x'));
// x1 place: Winnie
// x2 place: Tim
// x3 place: Bang

2、匹配结尾 $

$ 用来匹配字符串的结尾,在多行检索中,匹配每一行的结尾。

示例:

var str = `s1 place: Winnie
s2 place: Header
s3 place: Footer`;

var pattern1 = /[er]$/g;
var pattern2 = /[er]$/gm;

console.log(str.replace(pattern1, 'x'));
// s1 place: Winnie
// s2 place: Header
// s3 place: Footex

console.log(str.replace(pattern2, 'x'));
// s1 place: Winnix
// s2 place: Headex
// s3 place: Footex

3、匹配单词边界的位置 ╲b

\b 用来匹配一个单词的边界,即指定值为单词边界时才完成匹配(注意 [\b] 匹配的是退格符)

示例:

var str = 'Leophen';
var pattern1 = /ph/;
var pattern2 = /ph\b/;
var pattern3 = /en\b/;

console.log(str.replace(pattern1, 'x')); // Leoxen
console.log(str.replace(pattern2, 'x')); // Leophen 这里 ph 不是单词边界,所以不匹配 ph
console.log(str.replace(pattern3, 'x')); // Leophx

4、匹配非单词边界的位置 ╲B

\B 用来匹配非单词边界的位置,即指定值不是单词边界才完成匹配。

示例:

var str = 'Leophen';
var pattern1 = /en/;
var pattern2 = /en\B/;
var pattern3 = /ph\B/;

console.log(str.replace(pattern1, 'x')); // Leophx
console.log(str.replace(pattern2, 'x')); // Leophen 这里 en 是单词边界,所以不匹配 en
console.log(str.replace(pattern3, 'x')); // Leoxen

5、要求后面是 p (?=p)

(?=p) 用来零宽正向先行断言,要求接下来的字符都与 p 匹配,但不能包括匹配 p 的那些字符。

var str = 'Leophen';

var pattern1 = /(Leo(?=phen))/;
var pattern2 = /(Leo(?=phe))/;
var pattern3 = /(Leo(?=x))/;

console.log(pattern1.test(str)); // true 捕获 Leo 时抢先看接下来是否为 phen
console.log(pattern2.test(str)); // true
console.log(pattern3.test(str)); // false

6、要求后面不是 p (?!p)

(?!p) 用来零宽负向先行断言,要求接下来的字符串不与 p 匹配。

var str = 'Leophen';

var pattern1 = /(Leo(?!x))/;
var pattern2 = /(Leo(?!p))/;

console.log(pattern1.test(str)); // true 要求 Leo 后面不能为 x
console.log(pattern2.test(str)); // false

五、正则表达式量词

1、匹配 n 次 {n}

{n} 匹配前一项 n 次。

2、至少匹配 n 次 {n, }

{n, } 匹配前一项 n 或更多次。

3、匹配 n 到 m 次 {n, m}

{n, m} 匹配前一项至少 n 次,但不能超过 m 次。

4、可有(1 次)可无 ?

? 匹配前一项 0 或 1 次,也就是说前一项是可选的,等价于 {0, 1}

5、匹配至少一次 +

+ 匹配前一项 1 或多次,等价于 {1, }

5、匹配任意次 *

* 匹配前一项 0 次或多次,等价于 {0, }

综合示例:

var str = 'aaab';

console.log(/a{0}/.exec(str)); // ""
console.log(/a{1}/.exec(str)); // "a"
console.log(/a{1,}/.exec(str)); // "aaa"
console.log(/a{2,}/.exec(str)); // "aaa"
console.log(/a{1,2}/.exec(str)); // "aa"
console.log(/a{1,3}/.exec(str)); // "aaa"
console.log(/a+/.exec(str)); // "aaa"
console.log(/a+?/.exec(str)); // "a"
console.log(/a+b/.exec(str)); // "aaab"
console.log(/a+?b/.exec(str)); // "aaab"

六、正则表达式分组和范围

1、匹配 a 或 b a|b

| 表示选择,匹配该符号左右边的任一字符。

  • 示例:/green|red/"green apple" 里匹配 "green",且在 "red apple" 里匹配 "red"

2、组合并记忆匹配项 (…)

(…) 表示组合(捕获组),将几个项组合为一个单元,这个单元可通过 “*”、“+”、“?” 和 “|” 等符号加以修饰,而且可以记住和这个组相匹配的字符串以供此后的任何使用。

3、组合但不记忆匹配项 (?: …)

(?: …) 表示只组合(非捕获组),把项组合到一个单元,但是不记忆与改组相匹配的字符。

4、反向引用 ╲n

\n 中的 n 是一个正整数,表示和第 n 个分组第一次匹配的字符相匹配,组是圆括号中的子表达式(也有可能是嵌套的),组索引是从左到右的左括号数,(?: 形式的分组不编码。

综合示例:

var str1 = 'abcd';

console.log(/(ab)c/.exec(str1)); // "abc", "ab"
console.log(/(?:ab)c/.exec(str1)); // "abc"
console.log(/(ab)(c)/.exec(str1)); // "abc", "ab", "c"
console.log(/(a(b(c)))/.exec(str1)); // "abc", "abc", "bc", "c"

var str2 = 'ab cd ab';
console.log(/(ab) cd \1/.exec(str2)); // "ab cd ab", "ab"

七、用于模式匹配的 String 方法

1、search()

str.search(searchvalue)

功能:查找匹配值的起始位置。

参数:searchvalue(必须):要查找的字符串或正则表达式(忽略全局匹配 g)。

返回值:所匹配到的第一个字符串的起始位置。

示例:

const str = 'Hello, welcome to Leophen Blog.';

console.log(str.search('welco', 'x')); // 7
console.log(str.search(/welco/, 'x')); // 7
console.log(str.search(/welco/g, 'x')); // 7
console.log(str.search('welcx', 'x')); // -1
console.log(str); // Hello, welcome to Leophen Blog.
  • 如果 search() 的参数不是正则表达式,则首先会通过 RegExp 构造函数将它转换为正则表达式。
  • search() 不支持全局检索,因为它忽略修饰符 g。

2、replace()

str.replace(searchvalue, newvalue)

功能:替换匹配的内容。

参数:

  • searchvalue(必须):如果为被替换的字符串,则替换第一个匹配项;如果为正则表达式,则替换正则表达式匹配到的内容。
  • newvalue(必须):替换文本。

返回值:替换后的新字符串。

示例:

const str = 'Hello, welcome to Leophen Blog.';

console.log(str.replace('o', 'x')); // Hellx, welcome to Leophen Blog.
console.log(str.replace(/o/, 'x')); // Hellx, welcome to Leophen Blog.
console.log(str.replace(/o/g, 'x')); // Hellx, welcxme tx Lexphen Blxg.
console.log(str); // Hello, welcome to Leophen Blog.
  • 正则表达式如果设置的修饰符 g,则进行全局替换,否则只替换匹配的第一个子串。
  • 如果第一个参数不是正则表达式,则直接搜索该字符串,而不是将其转换为正则表达式。

3、match()

str.match(regexp)

功能:根据正则表达式返回匹配到的字符串。

参数:regexp(必须):指定的正则表达式对象。

返回值:

  • regexp 使用 g,返回存放匹配结果的数组。
  • regexp 未使用 g,仅返回第一个匹配到的捕获组(Array)

示例:

const str = 'Hello, welcome to Leophen Blog.';

const regex1 = /[A-Z]/;
console.log(str.match(regex1));
// ['H', index: 0, input: 'Hello, welcome to Leophen Blog.', groups: undefined]

const regex2 = /[A-Z]/g;
console.log(str.match(regex2)); // ['H', 'L', 'B']

它的参数如果不是正则表达式则通过 RegExp 转换,返回的是一个由匹配结果组成的数组。

4、split()

str.split([separator[, limit]])

功能:把字符串分割为字符串数组,是 Array.join( ) 的逆操作。

参数:

  • separator(必须):字符串或正则表达式,从该参数指定的地方分割原字符串。
  • howmany(可选):指定返回数组的最大长度。

返回值:分割后的字符串数组。

示例:

var str = 'Hi, visitor';

console.log(str.split('')); // ['H', 'i', ',', ' ', 'v', 'i', 's', 'i', 't', 'o', 'r']
console.log(str.split(' ')); // ['Hi,', 'visitor']
console.log(str.split(/\s/)); // ['Hi,', 'visitor']
console.log(str.split(' ', 1)); // ['Hi,']
console.log(str); // Hi, visitor

「点击查询正则表达式 RegExp 对象的属性和方法」

八、常见的正则表达式

1、姓名

/^[\u4e00-\u9fa5]{2,4}$/

2、身份证号

/^\d{17}[0-9x]$/

3、邮箱

/^\w+@\w+.[a-zA-Z]{2,3}(.[a-zA-Z]{2,3})?$/

4、手机号

/^\d{11}$/