资讯专栏INFORMATION COLUMN

《JavaScript 正则表达式迷你书》知识点小抄本

zollero / 859人阅读

摘要:介绍这周开始学习老姚大佬的正则表达式迷你书,然后习惯性的看完一遍后,整理一下知识点,便于以后自己重新复习。感谢原书作者老姚,本文无意抄袭,只是作为自己知识点的整理,后续也会整理到自己的知识库网站中。等价于,表示出现次。

介绍

这周开始学习老姚大佬的《JavaScript 正则表达式迷你书》 , 然后习惯性的看完一遍后,整理一下知识点,便于以后自己重新复习。

我个人觉得:自己整理下来的资料,对于知识重现,效果不错。

感谢原书作者老姚,本文无意抄袭,只是作为自己知识点的整理,后续也会整理到自己的 JavaScript知识库——《Cute-JavaScript》 网站中。

另外,请读者们注意,这篇文章是知识点的整理,方便复习,所以不会介绍太详细,因为毕竟原书写得非常棒,刚入门的朋友,我还是建议看下原书。

然后可以看看这篇文章,来回顾重要知识点。

《JavaScript 正则表达式迷你书》

《Cute-JavaScript》

目录

一、正则表达式字符匹配

二、正则表达式位置匹配

三、正则表达式括号的使用

四、正则表达式回溯法原理

五、正则表达式的拆分

六、正则表达式的构建

七、正则表达式编程

文章推荐(补充中)

老姚 —— JS正则表达式完整教程

常见的正则表达式可视化描述

工具推荐

Regulex*%3F%24)

Rubular

一、正则表达式字符匹配

原书这么一句话,特别棒:正则表达式是匹配模式,要么匹配字符,要么匹配位置,要记住。

1. 两种模糊匹配

正则表达式的强大在于它的模糊匹配,这里介绍两个方向上的“模糊”:横向模糊和纵向模糊。

横向模糊匹配

即一个正则可匹配的字符串长度不固定,可以是多种情况。

/ab{2,5}c/ 表示匹配: 第一个字符是 "a" ,然后是 2 - 5 个字符 "b" ,最后是字符 "c"

let r = /ab{2,5}c/g;
let s = "abc abbc abbbc abbbbbbc";
s.match(r); // ["abbc", "abbbc"]

纵向模糊匹配

即一个正则可匹配某个不确定的字符,可以有多种可能。

/[abc]/ 表示匹配 "a", "b", "c" 中任意一个。

let r = /a[123]b/g;
let s = "a0b a1b a4b";
s.match(r); // ["a1b"]
2. 字符组

范围表示法

可以指定字符范围,比如 [1234abcdUVWXYZ] 就可以表示成 [1-4a-dU-Z] ,使用 - 来进行缩写。

如果要匹配 "a", "-", "z" 中任意一个字符,可以这么写: [-az][a-z][az-]

排除字符组

即需要排除某些字符时使用,通过在字符组第一个使用 ^ 来表示取反,如 [^abc] 就表示匹配除了 "a", "b", "c" 的任意一个字符。

常见简写形式

字符组 具体含义
d 表示 [0-9],表示一位数字。
D 表示 [^0-9],表示除数字外的任意字符。
w 表示 [0-9a-zA-Z_],表示数字、大小写字母和下划线。
W 表示 [^0-9a-zA-Z_],表示非单词字符。
s 表示 [ v f],表示空白符,包含空格、水平制表符、垂直制表符、换行符、回车符、换页符。
S 表示 [^ v f],表示非空白字符。
. 表示 [^ u2028u2029] 。通配符,表示几乎任意字符。换行符、回车符、行分隔符和段分隔符除外。

然后表示任意字符,就可以使用 [dD][wW][sS][^] 任意一个。

3. 量词

量词也称重复,常用简写如下:

量词 具体含义
{m,} 表示至少出现 m 次。
{m} 等价于 {m, m} ,表示出现 m 次。
? 等价于 {0, 1} ,表示出现或不出现。
+ 等价于 {1, } ,表示至少出现1次。
* 等价于 {0, } ,表示出现任意次,也有可能不出现。

贪婪匹配和惰性匹配

在正则 /d{2,4}/ ,表示数字连续出现 2 - 4 次,可以匹配到 2 位、 3 位、4 位连续数字。

但是在 贪婪匹配/d{2,4}/g ,会尽可能多匹配,如超过 4 个,就只匹配 4 个,如有 3 个,就匹配 3 位。

而在 惰性匹配/d{2,4}?/g ,会 尽可能少 匹配,如超过 2 个,就只匹配 2 个,不会继续匹配下去。

let r1 = /d{2,4}/g;
let r2 = /d{2,4}?/g;
let s  = "123 1234 12345"; 
s.match(r1); // ["123", "1234", "1234"]
s.match(r2); // ["12", "12", "34", "12", "34"]
惰性量词 贪婪量词
{m,m}? {m,m}
{m,}? {m,}
?? ?
+? +
*? *
4. 多选分支

即提供多个子匹配模式任选一个,使用 |(管道符)分隔,由于分支结构也是惰性,即匹配上一个后,就不会继续匹配后续的。

格式如:(r1|r2|r3),我们就可以使用 /leo|pingan/ 来匹配 "leo""pingan"

let r = /leo|pingan/g;
let s = "leo cool,pingan good.";
s.match(r);// ["leo", "pingan"]

// 多选分支的惰性表现
let r1 = /leo|leooo/g;
let r2 = /leooo|leo/g;
let s  = "leooo";
s.match(r1);// ["leo"]
s.match(r2);// ["leooo"]
5. 案例分析

匹配字符,无非就是字符组、量词和分支结构的组合使用。

十六进制颜色值匹配

let r = /#[0-9a-fA-F]{6}|#[0-9a-fA-F]{3}/g;
let s = "#ffaacc #Ff00DD #fFF #01d #9Gd";
s.match(r); // ["#ffaacc", "#Ff00DD", "#fFF", "#01d"]

时间和日期匹配

// 时间 12:23 或 01:09
let r = /^([01][0-9]|[2][0-3]):[0-5][0-9]$/;  
r.test("23:25"); // true
r.test("03:05"); // true

// 时间 12:23 或 1:9
let r = /^(0?[0-9]|1[0-9]|[2][0-3]):(0?[0-9]|[1-5][0-9])$/;  
r.test("23:25"); // true
r.test("03:05"); // true
r.test("3:5");   // true

// 日期 yyyy-mm-dd
let r = /^[0-9]{4}-(0[1-9]|[1][0-2])-(0[1-9]|[12][0-9]|3[01])$/;
r.test("2019-09-19"); // true
r.test("2019-09-32"); // false

Windows操作系统文件路径匹配

盘符使用 [a-zA-Z]: ,这里需要注意 字符需要转义,并且盘符不区分大小写;
文件名或文件夹名,不能包含特殊字符,使用 [^:*<>|"? /] 表示合法字符;
并且至少有一个字符,还有可以出现任意次,就可以使用 ([^:*<>|"? /]+)* 匹配任意个 文件夹
还有路径最后一部分可以是 文件夹 ,即没有 于是表示成 ([^:*<>|"? /]+)?

let r = /^[a-zA-Z]:([^:*<>|"?
/]+)*([^:*<>|"?
/]+)?$/;
r.test("C:documentleoa.png"); // true
r.test("C:documentleo");      // true
r.test("C:document");             // true
r.test("C:");                     // true

id匹配

如提取

中的 id="leo"

let r1 = /id=".*"/;    // tips1
let r2 = /id=".*?"/;   // tips2
let r3 = /id="[^"]*"/; // tips3

let s  = "
"; s.match(r1)[0]; // id="leo" class="good" s.match(r2)[0]; // id="leo" s.match(r3)[0]; // id="leo"

tips1:由于 . 匹配双引号,且 * 贪婪,就会持续匹配到最后一个双引号结束。
tips2:使用惰性匹配,但效率低,有回溯问题。
tips3:最终优化。

二、正则表达式位置匹配

位置匹配,就是要匹配每个字符两边的位置。

ES5 中有6个位置: ^$B(?=p)(?!p)

另外把位置理解成空字符是非常有用的:

/^^hello$$/.test("hello");  // true
/^^^hello$$/.test("hello"); // true
1. ^ 和 $

^ 匹配开头,多行中匹配行开头。
$ 匹配结尾,多行中匹配行结尾。

"hello".replace(/^|$/g, "#"); // "#hello#"
"hello
leo
haha".replace(/^|$/gm, "#");
/*
#hello#
#leo#
#haha#
*/

多行匹配模式使用 m 修饰符。

2. B

 匹配单词边界,即 wW 之间的位置,包括 w^ 之间的位置,和 w$ 之间的位置。
B 相反,即非单词边界,匹配中除去 ,剩下的都是 B 的。
也就是 wwWW^WW$ 之间的位置。。

"[HI] Leo_1.mp4".replace(//g,"#");
// "[#HI#] #Leo_1#.#mp4#"

"[HI] Leo_1.mp4".replace(/B/g,"#");
// "#[H#I]# L#e#o#_#1.m#p#4"
3. (?=p)(?!p)

p 为一个子模式,即 (?=p) 匹配前面是 p 的位置,而 (?!p) 则匹配前面不是 p 的位置。

"hello".replace(/(?=l)/g, "#");
// "he#l#lo"

"hello".replace(/(?!l)/g, "#");
// "#h#ell#o#"
4. 相关案例

匹配数字千位分隔符

// 匹配最后一个逗号
"12345678".replace(/(?=d{3}$)/g, ","); // "12345,678"

// 匹配所有逗号
"12345678".replace(/(?=(d{3})+$)/g, ","); // "12,345,678"

// 匹配其余
"123456789".replace(/(?=(d{3})+$)/g, ","); // ",123,456,789"

// 修改
"123456789".replace(/(?!^)(?=(d{3})+$)/g, ","); // "12,345,678"

// 其他形式
"12345678 123456789".replace(/(?!)(?=(d{3})+)/g, ","); 
// (?!) 等于 B ,要求当前是一个位置,但不是  前面的位置
// "12,345,678 123,456,789"

数据格式化

let num = 1888;
num.toFixed(2).replace(/B(?=(d{3})+)/g, ",").replace(/^/,"$$ ");
// "$ 1,888.00"

验证密码

// 密码长度 6-12 位数字或字母
let r = /^[0-9A-Za-z]{6,12}$/;

// 必须包含一个字符(数字) + 密码长度 6-12 位数字或字母
let r = /(?=.*[0-9])^[0-9A-Za-z]{6,12}$/;

// 必须包含两个个字符(数字和小写字符)  + 密码长度 6-12 位数字或字母
let r = /(?=.*[0-9])(?=.*[a-z])^[0-9A-Za-z]{6,12}$/;

r.test("aa1234566"); // true
r.test("1234566");   // false


// 密码长度 6-12 位数字或字母 
// 即 不能全是数字 或 不能全是大写或小写字母
let r = /(?!^[0-9]{6,12}$)(?!^[a-z]{6,12}$)(?!^[A-Z]{6,12}$)^[0-9A-Za-z]{6,12}$/;
三、正则表达式括号的使用

简单理解:括号提供了分组,便于我们使用它。

通常有两种引用情况:在JS代码中引入,和在正则表达式中引入

分组和分支结构,主要是强调括号内是一个整体,即提供子表达式。

分组如 /(ab)+/g 匹配连续出现的 ab

分支结构如 /(a|b)+/g 匹配出现的 ab 表达式。

1.分组引用

如在日期匹配的时候,就可以这么改造:

// 原来
let r = /d{4}-d{2}-d{2}/;

// 现在
let r = /(d{4})-(d{2})-(d{2})/;

提取数据

"2019-03-14".match(r);
r.exec("2019-03-14");
// ["2019-03-14", "2019", "03", "14", index: 0, input: "2019-03-14"]

RegExp.$1; // "2019"
RegExp.$2; // "03"
RegExp.$3; // "14"

替换

yyyy-mm-dd 转成 mm/dd/yyyy

"2019-03-14".replace(r, "$2/$3/$1");
// 等价于
"2019-03-14".replace(r, function(){
    return RegExp.$2 + "/" + RegExp.$3 + "/" + RegExp.$1;
});
2. 反向引用

使用 表示第 n 个分组,比如 1 表示第 1 个分组:

let r = /d{4}(-|/|.)d{2}1d{2}/;
r.test("2019-03-15");
r.test("2019/03/15");
r.test("2019.03.15");
r.test("2019-03/15");

多个括号嵌套

按照开括号的顺序:

let r = /^((d)(d(d)))1234$/;
let s = "1231231233";
r.test(s);
console.log([RegExp.$1,RegExp.$2,RegExp.$3,RegExp.$4]);
// ["123", "1", "23", "3"]

特殊情况

10 表示的是第 10 个分组,若要匹配 0 时,使用 (?:1)01(?:0)

let r = /(1)(2)(3)(4)(5)(6)(7)(8)(9)(#) 10+/;
let s = "123456789# #####";
r.test(s);  // true

当引用不存在的分组

如匹配 2 是前面不存在,则匹配 2 本身,即对 2 的转义,不同浏览器可能不同:

let r = /1234/;
r.test("1234");  // true
"1234".split("");// ["", "", "", ""]

分组后面有量词

当分组后面有量词的话,则捕获的是最后一次的匹配:

"12345".match(/(d)+/); // ["12345", "5", index: 0, input: "12345"]

/(d)+ 1/.test("12345 1"); // false
/(d)+ 1/.test("12345 5"); // true
3. 相关案例

这里只写出核心代码。

模拟字符串 trim 方法

// 1 匹配首尾空白符,替换成空字符
"  aaa   ".replace(/^s+|s+$/g, "");      // "aaa"

// 2 匹配整个字符串,再用引用提取对应数据
"  aaa   ".replace(/^s*(.*?)s*$/g, "$1");// "aaa"

每个单词首字母大写

"hi leo hi boy!".toLowerCase().replace(
    /(?:^|s)w/g, 
    c => c.toUpperCase()
);
// "Hi Leo Hi Boy!"

驼峰化 和 中划线化

"-leo-and-pingan".replace(/[-_s]+(.)?/g,
    (match, c) => c ? c.toUpperCase() : ""
);
// "LeoAndPingan"

"LeoAndPingan".replace(/([A-Z])/g, "-$1").replace(
    /[-_s]+g/,"-"
).toLowerCase();
// "-leo-and-pingan"

匹配成对HTML标签

匹配成对标签

leo

,而不匹配不成对标签

leo

let r = /<([^>]+)>[dD]*/;
r.test("

leo leo leo

"); // true r.test("leo leo leo"); // true r.test("

leo leo leo

"); // false
四、正则表达式回溯法原理

概念理解起来比较容易。
比如用 /ab{1,3}c/ 去匹配下面两个字符串。

当匹配 abbbc,按顺序匹配,到了第 3 个 b 后,直接匹配 c,这样就没有回溯。

当匹配 abbc,按顺序匹配,到了第 2 个 b 后,由于规则是 b{1,3} ,则会继续往下匹配,然后发现下一位是 c,于是回退到前一个位置,重新匹配,这就是回溯。

另外像 /".*"/ 来匹配 "abc"de 的话,就会有三个回溯情况,为了减少不必要的回溯,我们可以把正则修改为 /"[^"]*"/

介绍

回溯法,也称试探法,本质上是深度优先探索算法,基本思路是:匹配过程中后退到之前某一步重新探索的过程。

1. 常见的回溯形式

贪婪量词

多个贪婪量词挨着存在,并相互冲突时,会看匹配顺序,深度优先搜索:

"12345".match(/(d{1,3})(d{1,3})/);
//  ["12345", "123", "45", index: 0, input: "12345"]

惰性量词

有时候会因为回溯,导致实际惰性量词匹配到的不是最少的数量:

"12345".match(/(d{1,3}?)(d{1,3})/);
// 没有回溯的情况 ["1234", "1", "234", index: 0, input: "12345"]

"12345".match(/^d{1,3}?d{1,3}$/);
// 有回溯的情况 ["12345", index: 0, input: "12345"]

分支结构

分支机构,如果一个分支整体不匹配,会继续尝试剩下分支,也可以看成一种回溯。

"candy".match(/can|candy/); // ["can", index: 0, input: "candy"]

"candy".match(/^(?:can|candy)$/); // ["candy", index: 0, input: "candy"]
2. 本章小结

简单总结:一个个尝试,直到,要么后退某一步整体匹配成功,要么最后试完发现整体不匹配。

贪婪量词:买衣服砍价,价格高了,便宜点,再便宜点。

懒惰量词:卖衣服加价,价格低了,多给点,再多给点。

分支结构:货比三家,一家不行换一家,不行再换。

五、正则表达式的拆分

拆分正则代码块,是理解正则的关键。

在 JavaScrip 正则表达式有以下结构:

字面量: 匹配一个具体字符,如 a 匹配字符 a

字符组: 匹配一个有多种可能性的字符,如 [0-9] 匹配任意一个数字。

量词: 匹配一个连续出现的字符,如 a{1,3} 匹配连续最多出现 3 次的a字符。

锚: 匹配一个位置,如 ^ 匹配字符串的开头。

分组: 匹配一个整体,如 (ab) 匹配 ab 两个字符连续出现。

分支: 匹配一个或多个表达式,如 ab|bc 匹配 abbc 字符。

另外还有以下操作符:

优先级 操作符描述 操作符
1 转义符
2 括号和方括号 (...)/(?:...)/(?=...)/(?!...)/[...]
3 量词限定符 {m}/{m,n}/{m,}/?/*/+
4 位置和序列 ^/$/元字符/一般字符
5 管道符 ` `

Tips:优先级从上到下,由高到低。

1. 注意要点

匹配字符串整体

不能写成 /^abc|bcd$/ ,而是要写成 /^(abc|bcd)$/

量词连缀问题

需要匹配:每个字符是 a/b/c 中其中一个,并且字符串长度是 3 的倍数:

不能写成 /^[abc]{3}+$/ ,而是要写成 /([abc]{3})+/

元字符转义问题

元字符就是正则中的特殊字符,当匹配元字符就需要转义,如:

^$.*+?|/()[]{}=!:-

// "[abc]"  => /[abc]/ 或者 /[abc]/ 
// "{1,3}"  => /{1}/ 或者 /{1}/ 因为不构成字符组
2. 案例分析

身份证号码

/^(d{15}|d{17})[dxX]$/.test("390999199999999999");// true

IPV4地址

需要好好分析:

let r = /^((0{0,2}d|0?d{2}|1d{2}|2[0-4]d|25[0-5]).){3}(0{0,2}d|0?d{2}|1d{2}|2[0-4]d|25[0-5])$/
六、正则表达式的构建

正则的构建需要考虑以下几点的平衡:

匹配预期的字符串

不匹配非预期的字符串

可读性和可维护性

效率

我们还需要考虑这么几个问题:

是否需要使用正则

如能使用其他 API 简单快速解决问题就不需要使用正则:

"2019-03-16".match(/^(d{4})-(d{2})-(d{2})/); // 间接获取 ["2019", "03", "16"]
"2019-03-16".split("-"); //  ["2019", "03", "16"]

"?id=leo".search(/?/); // 0
"?id=leo".indexOf("?"); // 0

"JavaScript".match(/.{4}(.+)/)[1];  // "Script"
"JavaScript".substring(4);          // "Script"

是否需要使用复杂正则

/(?!^[0-9]{6,12}$)(?!^[a-z]{6,12}$)(?!^[A-Z]{6,12}$)^[0-9A-Za-z]{6,12}$/

将这个正则拆分成多个小块,如下:

var regex1 = /^[0-9A-Za-z]{6,12}$/;
var regex2 = /^[0-9]{6,12}$/;
var regex3 = /^[A-Z]{6,12}$/;
var regex4 = /^[a-z]{6,12}$/;
function checkPassword (string) {
    if (!regex1.test(string)) return false;
    if (regex2.test(string)) return false;
    if (regex3.test(string)) return false;
    if (regex4.test(string)) return false;
    return true;
}
1. 准确性

即需要匹配到预期目标,且不匹配非预期的目标。

匹配固定电话

如需要匹配下面固定电话号码,可以分别写出对应正则:

055188888888     => /^0d{2,3}[1-9]d{6,7}$/
0551-88888888    => /^0d{2,3}-[1-9]d{6,7}$/
(0551)88888888   => /^0d{2,3}-[1-9]d{6,7}$/

然后合并:

let r = /^0d{2,3}[1-9]d{6,7}$|^0d{2,3}-[1-9]d{6,7}$|^(0d{2,3})[1-9]d{6,7}$/

然后提取公共部分:

let r = /^(0d{2,3}|0d{2,3}-|(0d{2,3}))[1-9]d{6,7}$/

再优化:

let r = /^(0d{2,3}-?|(0d{2,3}))[1-9]d{6,7}$/

匹配浮点数

先确定,符号部分([+-])、整数部分(d+)和小数部分(.d+)。

1.23、+1.23、-1.23  => /^[+-]?d+.d+$/
10、+10、-10        => /^[+-]?d+$/
.2、+.2、-.2        => /^[+-]?.d+$/

整理后:

let r = /^[+-]?(d+.d+|d+|.d+)$/;

// 考虑不匹配 +.2 或 -.2
let r = /^([+-])?(d+.d+|d+|.d+)$/;

// 考虑不匹配 012 这类 0 开头的整数
let r = /^[+-]?(d+)?(.)?d+$/;
2. 效率

正则表达式运行过程:

编译

设定起始位置

尝试匹配

若匹配失败则返回前一步重新匹配

返回匹配成功失败的结果

我们常常优化对 3 和 4 步进行优化:

使用具体字符组替代通配符,消除回溯

/"[^"]*"/ 代替 /".*?"/

使用非捕获型分组

当不需要使用分组引用和反向引用时,此时可以使用非捕获分组。

/^[-]?(?:d.d+|d+|.d+)$/ 代替 /^[-]?(d.d+|d+|.d+)$/

独立出确定字符

加快判断是否匹配失败,进而加快移位的速度。

/aa*/ 代替 /a+/

提取分支公共部分

减少匹配过程中可消除的重复。

/^(?:abc|def)/ 代替 /^abc|^def/

减少分支的数量,缩小它们的范围

/rea?d/ 代替 /red|read/

七、正则表达式编程

这里要掌握正则表达式怎么用,通常会有这么四个操作:

验证

切分

提取

替换

1. 四种操作

验证

匹配本质上是查找,我们可以借助相关API操作:

// 检查字符串是否包含数字
let r = /d/, s = "abc123";
!!s.search(r); // true
r.test(s);     // true
!!s.match(r);  // true
!!r.exec(s);   // true

切分

"leo,pingan".split(/,/); // ["leo", "pingan"]

let r = /D/, s = "2019-03-16";
s.split(r);   // ["2019", "03", "16"]
s.split(r);   // ["2019", "03", "16"]
s.split(r);   // ["2019", "03", "16"]

提取

// 提取日期年月日
let r = /^(d{4})D(d{2})D(d{2})$/;
let s = "2019-03-16";

s.match(r); // ["2019-03-16", "2019", "03", "16", index: 0, input: "2019-03-16"]
r.exec(s);  // ["2019-03-16", "2019", "03", "16", index: 0, input: "2019-03-16"]
r.test(s);  // RegExp.$1 => "2019" RegExp.$2 => "03" RegExp.$3 => "16"
s.search(r);// RegExp.$1 => "2019" RegExp.$2 => "03" RegExp.$3 => "16"

替换

// yyyy-mm-dd 替换成 yyyy/mm/dd
"2019-03-16".replace(/-/g, "/");
2. 相关API注意

searchmatch 参数问题

这两个方法会把字符串转换成正则,所以要加转义

let s = "2019.03.16";
s.search(".");    // 0
s.search(".");  // 4
s.search(/./);  // 4
s.match(".");     // ["2", index: 0, input: "2019.03.16"]
s.match(".");   // [".", index: 4, input: "2019.03.16"]
s.match(/./);   // [".", index: 4, input: "2019.03.16"]

// 其他不用转义
s.split(".");
s.replace(".", "/");

match 返回结果的格式问题

match 参数有 g 会返回所有匹配的内容,没有 g 则返回标准匹配格式:

let s = "2019.03.16";
s.match(/(d+)/);  // ["2019", "2019", index: 0, input: "2019.03.16"]
s.match(/(d+)/g); // ["2019", "03", "16"]

test 整体匹配时需要使用 ^$

/123/.test("a123b");    // true
/^123$/.test("a123b");  // false
/^123$/.test("123");    // true

split 的注意点

split 第二个参数是 结果数组的最大长度

"leo,pingan,pingan8787".split(/,/, 2); // ["leo", "pingan"]

使用正则分组,会包含分隔符:

"leo,pingan,pingan8787".split(/(,)/); // ["leo", ",", "pingan", ",", "pingan8787"]

修饰符

修饰符 描述
g 全局匹配,即找到所有匹配的,单词是 global
i 忽略字母大小写,单词是 ingoreCase
m 多行匹配,只影响 ^$,二者变成行的概念,即行开头和行结尾。单词是 multiline

文章到这结束,感谢阅读,也感谢老姚大佬的这本书

Author 王平安
E-mail pingan8787@qq.com
博 客 www.pingan8787.com
微 信 pingan8787
每日文章推荐 https://github.com/pingan8787...
ES小册 js.pingan8787.com
微信公众号

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/102610.html

相关文章

  • 正则达式

    摘要:本文内容共正则表达式火拼系列正则表达式回溯法原理学习正则表达式,是需要懂点儿匹配原理的。正则表达式迷你书问世了让帮你生成和解析参数字符串最全正则表达式总结验证号手机号中文邮编身份证地址等是正则表达式的缩写,作用是对字符串执行模式匹配。 JS 的正则表达式 正则表达式 一种几乎可以在所有的程序设计语言里和所有的计算机平台上使用的文字处理工具。它可以用来查找特定的信息(搜索),也可以用来查...

    bang590 评论0 收藏0
  • JavaScript正则达式迷你-笔记

    摘要:比如正则表示匹配这样一个字符串第一个字符是,接下来是到个字符,最后是字符。其实现的方式是使用字符组。具体形式如下,其中和是子模式,用管道符分隔,表示其中任何之一。 贪婪模式: 在使用修饰匹配次数的特殊符号时,有几种表示方法可以使同一个表达式能够匹配不同的次数,比如:{m,n}, {m,}, ?, *, +,具体匹配的次数随被匹配的字符串而定。这种重复匹配不定次数的表达式在匹配过程中,总...

    widuu 评论0 收藏0
  • 正则达式迷你-笔记

    摘要:使用看完你就会正则表达式了四种操作验证切分提取替换第一章正则表达式字符匹配攻略正则表达式是匹配模式,要么匹配字符,要么匹配位置至少,至多匹配中的任一个字符范围表示法如果要匹配则要么要么要么通配符,表示几乎任意 API 使用 String#search String#split String#match String#replace RegExp#test Reg...

    IamDLY 评论0 收藏0
  • 前端学习资源

    摘要:提供了完整的环境,并且支持自定义域名指向,动态计算资源调整,可以完成各种应用的开发编译与部署。 react 新特性 react16 Context 算法相关 图解排序算法(二)之希尔排序 微信小程序 微信小程序组件化的解决方案移动端尺寸基本知识 浏览器 前端必读:浏览器内部工作原理浏览器缓存原理解读浏览器加载css和js及dom解析之间的关系浏览器缓存 CSS学习 移动web开发布局入...

    zhisheng 评论0 收藏0
  • javascript正则迷你-笔记

    showImg(https://segmentfault.com/img/bVbfGSV?w=719&h=718); showImg(https://segmentfault.com/img/bVbfGTc?w=801&h=552); showImg(https://segmentfault.com/img/bVbfGTq?w=1017&h=501);

    LinkedME2016 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<