JS 正则表达式
正则表达式(Regular Expression)使用单个字符串来描述、匹配一系列符合某个句法规则的字符串搜索模式,是用于匹配字符串中字符组合的模式。
一、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
八、常见的正则表达式
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}$/