点击查看参考教程
参考内容参考链接
正则表达式学习正则表达式
特殊字符()正则表达式括号的作用
单词边界正则表达式单词边界和非单词边界

正则表达式的创建

两种方式进行创建:

使用一个正则表达式字面量,其由包含在斜杠之间的模式组成,如下所示:

var re = /\d/g;

调用RegExp对象的构造函数,如下所示:

var re = new RegExp("\\d", "g");

转移字符\要进行转义,写成\\


JS 中正则表达式的匹配

字符串的方法match进行匹配:

let str = "abca";
var re = /a/;
console.log(str.match(re)); //输出['a', index: 0, input: 'abca']

字符串的方法match进行匹配:

let str = "abca";
var re = /a/;
console.log(re.exec(str)); //输出['a', index: 0, input: 'abca']

其他匹配方法


正则表达式标志

标志 描述
g 全局搜索,所有正则表达式都有一个 lastIndex 属性,用于记录上一次匹配结束位置,如果没有设置全局匹配,那么 lastIndex 始终为 0
i 不区分大小写搜索
m 多行搜索,没有 m 则匹配整个文本;只会影响到 ^$
s 允许 . 匹配换行符
u 使用 unicode 码的模式进行匹配
y 执行“粘性(sticky)”搜索,匹配从目标字符串的当前位置开始

特殊字符

符号^

匹配输入开始。如果多行搜索标志被设置为 true,那么也匹配换行符后的位置。

无多行搜索

let str1 = "abc";
let str2 = "bac";
var re = /^a/;
console.log(re.exec(str1)); //输出['a', index: 0, input: 'abc']
console.log(re.exec(str2)); //输出null

正则表达式会匹配abc开头的a

有多行搜索

let str = `abcabc
abc`;
var re = /^a/gm;
console.log(str.match(re)); //输出['a', 'a']
console.log(re.exec(str)); //输出['a', index: 0, input: 'abcabc\nabc']
console.log(re.exec(str)); //输出['a', index: 7, input: 'abcabc\nabc']

注意多行文本使用的不是单引号而是反单引号

正则表达式会匹配字符串a开头,因为开启全局搜索g和多行搜索m,所以会对每一行进行匹配,所以会匹配文本每行开头的a

如果没有开启多行搜索m那么就会把文本当成一行进行匹配,所以只会匹配到开头的的一个a

符号$

匹配输入的结束。如果多行标志被设置为 true,那么也匹配换行符前的位置。

let str1 = "bca";
let str2 = "bac";
var re = /a$/;
console.log(re.exec(str1)); //输出['a', index: 2, input: 'bca']
console.log(re.exec(str2)); //输出null

正则表达式会匹配bca结尾的a

let str = `bcabca
bca`;
var re = /a$/gm;
console.log(str.match(re)); //输出['a', 'a']
console.log(re.exec(str)); //输出['a', index: 5, input: 'bcabca\nbca']
console.log(re.exec(str)); //输出['a', index: 9, input: 'bcabca\nbca']

注意多行文本使用的不是单引号而是反单引号

正则表达式会匹配字符串 a 结尾,有全局搜索 g 和多行搜索 m,会匹配每行开头的 a

符号{}

类型 含义
{n} n 是一个正整数,匹配了前面一个字符刚好出现了 n 次。
{n,} n 是一个正整数,匹配前一个字符至少出现了 n 次。
{n,m} n 和 m 都是整数。匹配前面的字符至少 n 次,最多 m 次。如果 n 或者 m 的值是 0, 这个值被忽略。

/a{2}/ 不会匹配“candy”中的’a’,但是会匹配“caandy”中所有的 a,以及“caaandy”中的前两个’a’。

/a{2,}/ 匹配 “aa”, “aaaa” 和 “aaaaa” 但是不匹配 “a”。

/a{1, 3}/ 匹配“candy”中的 a,匹配“caandy”中的前两个 a,也匹配“caaaaaaandy”中的前三个 a。

符号*

匹配前一个表达式 0 次或多次,等价于 {0,}

/bo*/ 会匹配 “A ghost boooooed” 中的 ‘booooo’ 和 “A bird warbled” 中的 ‘b’,但是在 “A goat grunted” 中不会匹配任何内容。

符号+

匹配前面一个表达式 1 次或者多次,等价于 {1,}

/a+/ 会匹配 “candy” 中的 ‘a’ 和 “caaaaaaandy” 中所有的 ‘a’,但是在 “cndy” 中不会匹配任何内容。

符号.

匹配除换行符之外的任何单个字符。如果设置标志 s 为 true 的话,也可以匹配换行符

/.n/ 将会匹配 “nay, an apple is on the tree” 中的 ‘an’ 和 ‘on’

符号|

x|y 匹配‘x’或者‘y’。

/green|red/ 匹配“green apple”中的‘green’和“red apple”中的‘red’

符号()

类型 含义
(X) 匹配 ‘x’ 并且记住匹配项。其中括号被称为捕获括号
(?:x) 匹配 ‘x’ 但是不记住匹配项。这种括号叫作非捕获括号
x(?=y) 匹配’x’当且仅当’x’后面是’y’,这种叫做先行断言。
(?<=y)x 匹配’x’当且仅当’x’前面是’y’,这种叫做后行断言。
x(?!y) 当且仅当’x’后面不是’y’时匹配’x’,这被称为正向否定查找。
(?<!y)x 当且仅当’x’前面不是’y’时匹配’x’,这被称为反向否定查找。

1.其中 (x) 的用法较多,分为三个部分

  1. 如果现在需要匹配连续的两个及以上的字符时,就需要使用 ()

    let str = "ababa abbb ababab";
    var re = /(ab)+/g;
    console.log(str.match(re)); //输出['abab', 'ab', 'ababab']
  2. 在分支结构中使用 (x|y)

    var re = /^hello (world|this is my blog)$/;
    console.log(re.test("hello world")); //true
    console.log(re.test("hello this is my blog")); //true

    如果没有添加括号可能会产生歧义,那么对于“hello world”、“this is my blog”、“hello this is my blog”、“hello world is my blog”都可以匹配成功

括号一个重要的功能就是捕获功能,它会记住捕获的字符串

var regex = /(\d{4})-(\d{2})-(\d{2})/;
var string = "2017-06-12";
console.log(regex.exec(string));
//输出["2017-06-12", "2017", "06", "12", index: 0, input: "2017-06-12"]
console.log(RegExp.$1); // 2017
console.log(RegExp.$2); // 06
console.log(RegExp.$3); // 12

执行 exec 输出的结果第一个元素是整体匹配的结果,然后是各个分组(括号里)匹配的内容,然后是匹配下标,最后是输入的文本。通过构造函数的全局属性 $1$9 可以获取详细的值。

如果想把 yyyy-mm-dd 格式,替换成 mm/dd/yyyy

var re = /(\d{4})-(\d{2})-(\d{2})/;
var str = "2017-06-12";
var result = str.replace(re, function () {
return (
(Number(RegExp.$2) + 1).toString().padStart(2, "0") +
"/" +
RegExp.$3 +
"/" +
RegExp.$1
);
});
console.log(result); // 07/12/2017

通过 replace 函数进行替换,通过 $1$2$3 来进行替换

如果要写一个正则支持匹配如下三种格式

2016-06-12

2016/06/12

2016.06.12

var re = /\d{4}(-|\/|\.)\d{2}\1\d{2}/;
var str1 = "2017-06-12";
var str2 = "2017/06/12";
var str3 = "2017.06.12";
var str4 = "2016-06/12";
console.log(re.test(str1)); // true
console.log(re.test(str2)); // true
console.log(re.test(str3)); // true
console.log(re.test(str4)); // false

通过这个正则表达式即可匹配成功,因为括号 (-|\/|\.) 会将匹配的内容记住,其中 \1 表示第一个括号匹配的字符串。

那么 \n (n 是整数)就代表第 n 个括号匹配的内容。

如果有括号嵌套,则以左括号为准判断第几个括号

var re = /^((\d)(\d(\d)))\1\2\3\4$/;
var str = "1231231233";
console.log(re.test(str)); // true
console.log(RegExp.$1); // 123
console.log(RegExp.$2); // 1
console.log(RegExp.$3); // 23
console.log(RegExp.$4); // 3

2.(?:x) 相比于 (x) 没有的捕获的功能,相当于一个原始的括号的功能

var re = /(?:ab)+/g;
var str = "ababa abbb ababab";
console.log(str.match(re)); // ["abab", "ab", "ababab"]

3.x(?=y)

/Jack(?=Sprat)/ 会匹配到’Jack’仅当它后面跟着’Sprat’。/Jack(?=Sprat|Frost)/ 匹配‘Jack’仅当它后面跟着’Sprat’或者是‘Frost’。但是‘Sprat’和‘Frost’都不是匹配结果的一部分。

4.(?<=y)x

/(?<=Jack)Sprat/ 会匹配到’ Sprat ‘仅仅当它前面是’ Jack '。/(?<=Jack|Tom)Sprat/ 匹配‘ Sprat ’仅仅当它前面是’Jack’或者是‘Tom’。但是‘Jack’和‘Tom’都不是匹配结果的一部分。

5.x(?!y)

仅当这个数字后面没有跟小数点的时候,/\d+(?!\.)/ 匹配一个数字。正则表达式 /\d+(?!\.)/.exec("3.141") 匹配‘141’而不是‘3.141’

6.(?<!y)x

仅当这个数字前面没有负号的时候,/(?<!-)\d+/ 匹配一个数字。/(?<!-)\d+/.exec('3') 匹配到 “3”。/(?<!-)\d+/.exec('-3') 因为这个数字前有负号,所以没有匹配到。

符号?

匹配前面一个表达式 0 次或者 1 次,等价于 {0,1}。如果 ? 紧跟任何量词 *、 +、? 或 {} 的后面,将会使量词变为非贪婪模式(匹配尽量少的字符)

  1. /e?le?/ 匹配 “angel” 中的 ‘el’、“angle” 中的 ‘le’ 以及 "oslo’ 中的 ‘l’。

  2. 贪婪模式

    如果想捕获一串字符串中的数字(可以 \d+ 匹配数字),通过如下方法

    let str = "abc1234567abc";
    var re = /.*(\d+).*$/;
    console.log(str.match(re));
    //['abc123456abc', '7', index: 0, input: 'hello 1234567 world']

    贪婪模式下会尽可能多的匹配,.* 可以匹配任意个非换行字符,所以 .* 会尽可能多的匹配字符,在贪婪模式下,.* 会匹配“abc123456”,留给捕获符号中的 \d+ 能够捕获的就是 7 ,这一个字符

  3. 非贪婪模式

    同样的将上面的 .* 改为非贪婪模式

    let str = "abc1234567abc";
    var re = /.*?(\d+).*$/;
    console.log(str.match(re));
    //['abc123456abc', '1234567', index: 0, input: 'hello 1234567 world']

    贪婪模式下会尽可能少的匹配字符,在碰到数字字符后会交给 \d+ ,所以可以捕获到“1234567”

符号[]

类型 含义
[xyz] 一个字符集合。匹配方括号中的任意字符,包括转义序列。你可以使用破折号(-)来指定一个字符范围。
[^xyz] 一个反向字符集。也就是说, 它匹配任何没有包含在方括号中的字符。你可以使用破折号(-)来指定一个字符范围。
[\b] 匹配转义字符\b 本身(匹配退格键\u0008)

正则表达式中,有些标点符号需要进行转义,如果不记得可以给每一个都加上转义符号“\”

  1. /[abcd]//[a-d]/ 是一样的。他们都匹配"brisket"中的‘b’。/[a-z.]+/ 与字符串“test.i.ng”匹配。

    console.log("brisket".match(/[abc]/)); //['b', index: 0, input: 'brisket']
    console.log("test.i.ng".match(/[a-z.]+/)); //['test.i.ng', index: 0, input: 'test.i.ng']
  2. /[^abc]//[^a-c]/ 是一样的。他们匹配"brisket"中的‘r’,也匹配“chop”中的‘h’。

    console.log("brisket".match(/[^a-c]/)); //['r', index: 1, input: 'brisket]

符号\w\W

\w:匹配一个单字字符(字母、数字或者下划线),等价于 [A-Za-z0-9_]

\W:匹配一个非单字字符,等价于 [^A-Za-z0-9_]

符号\b

匹配一个词的边界。

\b 它并不匹配字符,类似于 ^$ 起到的只是识别的作用,检查是否为边界

let str = `abc**abc
123`;
var re = /\w+\b/g;
var re1 = /\b.+?\b/gs;
console.log(str.match(re)); //['abc', 'abc', '123']
console.log(str.match(re1)); //['abc', '**', 'abc', '\n', '123']

非边界字符包括:大写和小写的罗马字母,十进制数字和下划线字符。对于其他的字符都会被视为断词,即会被视为边界。

在上面的匹配中“**”和换行符均会识别为边界,单词的前后均没有跟随的字符也被视为边界。如果以 | 符号当做边界符号的化,那么上面的 str 就可以划分为 |abc|**|abc|\n|123|

其他例子:

/\bm/ 匹配“moon”中的‘m’;
/oo\b/ 并不匹配"moon"中的’oo’,因为’oo’被一个“字”字符’n’紧跟着。
/oon\b/ 匹配"moon"中的’oon’,因为’oon’是这个字符串的结束部分。这样他没有被一个“字”字符紧跟着。

符号\B

匹配一个非单词边界。

和单词边界一样单词以 | 为边界字符串可以看成 |abc|**|abc|\n|123|,非单词边界就是将单词边界以外的地方当做边界,得到 a|b|c*|*a|b|c\n1|2|3,然后匹配边界内的内容是否符合要求

let str = `abc**abc
123`;
var re = /\B.+?\B/gs;
console.log(str.match(re)); //['b', 'c*', '*a', 'b', 'c\n1', '2']

正则表达式匹配所有非字符串边界中的字符,包括换行符,即要匹配的有“b”、“c*”、“*a”、“b”、“c\n1”、“2”这些字符

其他案例:

/\B../ 匹配"noonday"中的’oo’, 而 /y\B../ 匹配"possibly yesterday"中的’yes‘

符号\cX

当 X 是处于 A 到 Z 之间的字符的时候,匹配字符串中的一个控制符。

例如,/\cM/ 匹配字符串中的 control-M (U+000D),其他可查看控制字符

console.log(/\cM/.exec("123\u000D123")); //['\r', index: 3, input: '123\r123']

符号\d\D

\d:匹配一个数字,等价于[0-9]

\D:匹配一个非数字字符,等价于[^0-9]

其他字符

符号 含义
\f 匹配一个换页符 (U+000C)
\n 匹配一个换行符 (U+000A)
\r 匹配一个回车符 (U+000D)
\s 匹配一个空白字符,包括空格、制表符、换页符和换行符。等价于[ \f\n\r\t\v\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]
\S 匹配一个非空白字符。等价于 [^ \f\n\r\t\v\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]
\t 匹配一个水平制表符 (U+0009)
\v 匹配一个垂直制表符 (U+000B)
\0 匹配 NULL(U+0000)字符
\xhh 匹配一个两位十六进制数(\x00-\xFF)表示的字符
\uhhhh 匹配一个两位十六进制数(\x00-\xFF)表示的字符
\u{hhhh}\u{hhhhh} (仅当设置了 u 标志时)匹配一个十六进制数表示的 Unicode 字符。