正则表达式——学习笔记(JS)

正则表达式是很强大的工具,常用于字符串匹配与表单验证。以前只是在需要使用的时候百度一个,自己验证一下能满足使用场景就得过且过了,对原理并不了解。为长远着想,还是应该学习一下。

正则表达式的本质是描述一段字符串遵循的规则,其匹配模式主要有两种:匹配字符,匹配位置

通常情况下,匹配字符就能满足大多数场景,而匹配位置则更多地应用于验证

一、字符匹配

1.匹配模式

1.1横向模糊匹配——一个正则可匹配的字符长度不固定,使用量词计数字符出现次数的区间

模板:{m,n}表示最少连续出现m次,最多连续出现n次(特别注意,是连续出现

let regex = /ab{2,5}c/g;
// 表示 a 和 c 中间,b 最少连续出现2次,最多连续出现5次
let string = 'abc,abbc,abbccc,abbbb,abbbbbc,abbbbbbc';
console.log(string.match(regex));
// ['abbc', 'abbc', 'abbbbbc']

1.2纵向模糊匹配——具体到某一个字符的时候,它可以有多种可能

模板:[abc]表示该字符可以是 a, b, c中的任何一个

let regex = /a[123]b/g;
// 表示 a 和 c 中间的字符可以是 1, 2, 3
let string = 'a0b,a1b,a2b,a3b,a4b,a5b';
console.log(string.match(regex));
// ['a1b', 'a2b', 'a3b']

2.字符组——表示某一个字符所有的可能(只匹配一个字符)

上面的[123]就是一种字符组

2.1范围表示法——如果字符组中的字符特别多(即要匹配的字符有很多可能性),可用范围表示

模板:[123456abcdefGHIJKLM]可以写成[1-6a-fG-M](注意:使用范围表示法的前提是属于范围的字符需要时连续的, 12456就不能写成1-6,因为缺3)

let regex = /a[1-3f-zM-O]2/g;
let string = 'absa22,cag2m,daN2';
console.log(string.match(regex));
// ['a22', 'ag2', 'aN2']

特殊情况:如果需要匹配 '-' ,'a', 'z'中任意一个,要么改顺序[-az]或[az-],要么转义[a\-z],总之不能让引擎识别成范围表示

2.2排除字符组——某位字符可以是任何东西,但不能是'a', 'b', 'c',可以使用取反排除的概念

模板:[^abc],表示匹配的只以为字符可以是除了a,b,c的任一个。^(脱字符)表示求反

let regex = /a[^abc]3/g;
let string = 'bcaa3,ba63c,cda443,daG3M';
console.log(string.match(regex));
// ['a63', 'aG3']

2.3常见的字符组简写形式

\d[0-9]表示一位数字
\D[^0-9]表示数字以外的任一字符
\w[0-9a-zA-Z_]表示数字,字母,下划线
\W[^0-9a-zA-Z_]表示除了数字,字母,下划线的任一字符
\s[ \t\v\n\r\f]表示空白符,包括空格,水平制表符,垂直制表符,换行符,回车符,换页符
\S[^ \t\v\n\r\f]表示非空白符
.[^ \n\r\u20208\u2029]通配符,表示几乎所有字符。换行,回车,行分隔,段分隔除外

 

 

 

 

 

 

 

 

特殊技巧:匹配任意字符——[\d\D],[\w\W],[\s\S], [^]

3.量词

3.1简写形式

{ m, }下限为m,无上限
{ m }m次
?{ 0,1 },表示出现或不出现
+{ 1, },下限为1,无上限,即至少出现一次
*{ 0, },下限为0,无上限

 

 

 

 

 

 

3.2贪婪匹配和惰性匹配

贪婪匹配——会尽可能多的把符合条件里出现次数最多的匹配出来

let regex = /\d{2,5}/g;
// 表示数字连续出现2到5次
let string = '123,1234,12345,123456';
console.log(string.match(regex));
// ['123','1234', '12345', '12345']

连续数字出现2-5次都是符合的,但是因为是贪婪的,会尽可能长的匹配,所以如果5次符合,就匹配5次的。优先级是5次>4次>3次>2次

找12的时候其实已经符合条件了,但是因为是贪婪模式,所以发现123也符合,就继续了,直到,不匹配才重新从出现一次开始匹配

特别注意:匹配过的字符不会再次匹配,所以最后匹配到12345的时候就截断输出了,不会再匹配23456,因为前面的2345已经匹配过了

惰性匹配——再符合条件的匹配结果里尽可能少的匹配

let regex = /\d{2,5}?/g;
// 表示数字连续出现2到5次
let string = '123,1234,12345,123456';
console.log(string.match(regex));
//  ["12", "12", "34", "12", "34", "12", "34", "56"]

连续数字出现2-5次都是符合要求的,但是惰性匹配会优先匹配短的,只要出现2次符合就直接截断开始下一个匹配阶段,优先级是2>3>4>5

所以输出都是连续两个的数字

量词后加上?就能实现惰性匹配:{m,n}?    {m,}?    ??     +?     *?

4.多选分支——支持多个子模式任选其一,即符合其中一个模式就够了

模板:(p1 | p2 | p2),用 | (管道符)分隔,表示其中任一

let regex = /good|nice/g;
let string = 'good idea, nice boy';
console.log(string.match(regex));
// ["good", "nice"]

分支模式默认是惰性匹配的,当两个模式是包含关系的时候,前面匹配上了,后面的就不匹配了

let regex = /goodbye|good/g;
let string = 'goodbye';
console.log(string.match(regex));
// ["goodbye"]
let regex = /good|goodbye/g;
let string = 'goodbye';
console.log(string.match(regex));
// ["good"]

5.案例分析

匹配字符的本质无非就是字符组,量词和分支结构组合使用罢了

5.1匹配16进制颜色值

要求匹配:#ffbbad, #Fc01DF, #FFF, #ffE

要注意的是分支结构的顺序

let regex = /#\w{6}|\w{3}/g;

因为要求匹配6位或3位的,,所以量词直接使用{3}和{6},如果需要匹配4,5位的,则应该使用贪婪模式

5.2匹配时间(以24小时制为例)

要求匹配: 23:59        02:07

分析:第一位为2时,第二位为[0-3];第一位为[01]时,第二位为[0-9],第三位为[0-5],第四位为[0-9]

let regex = /^([01]\d|[2][0-3]):[0-5]\d$/;
console.log(regex.test('23:59'));
// true

注意:尾部不带g,不要全匹配;^匹配行开头,$匹配行结尾

如果也要求匹配  7:9 ,也就是时,分的高位为0可省略,正则如下:

let regex = /^(0?\d|1\d|2[0-3]):(0?\d|[1-5]\d)$/;
console.log(regex.test('3:9'));
// true

5.3匹配日期(比如 yyyy-mm-dd格式)

要求匹配: 2017-06-10

分析:年,四位数字表示即可——[0-9]{4}或\d{4}

月,共12个,分两种情况,高位为0和高位为1——(0[1-9]|1[0-2])

日,最大为31——(0[1-9]|[12]\d|3[01])

let regex = /^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$/;
console.log(regex.test('2017-06-10'));
// true

5.4windows操作系统文件路径

要求匹配: F:\study\javascript\regex\regular expression.pdf

F:\study\javascript\regex\

F:\study\javascript

F:\

分析:整体模式——盘符:\目录\目录\目录\

盘符,不区分大小写,注意:\ 要转义——[a-zA-Z]:\\

目录:不能包含特殊字符,使用取反;不能为空,用量词 + ;‘目录\’可能出现多次——([^\\:*<>|''?\r\n/]+\\)*

最后一部分可以没有\,因此要去掉\\,加上?——([^\\:*<>|"?\r\n/]+)?

5.5匹配标签的id

要求:从`<div id="container" class="main"></div>`字符串中提取id="container"

let regex = /id=".*?"/;
let string = `<div id="container" class="main"></div>`;
console.log(string.match(regex));

. 表示通配符,全匹配

* 量词,表示可多次出现

?惰性匹配,即从id="开始,再次匹配到"的时候结束

二、位置匹配

1.什么是位置?

可以理解为相邻字符之间的空字符。进行位置匹配的时候,尽量吧字符串理解成每个字符之间都有一个空字符

例如:hello = "h" + "" + "l" + "" + "l" + "" + "o";

2.如何匹配位置

需要使用锚字符来匹配:^   $   \b   \B   (?=p)   (?!p)

2.1 ^ 和 $

^(脱字符)匹配整个目标字符串的开头,在多行的情况下则匹配每一行的开头

$(美元符)匹配整个目标字符串的结尾,在多行的情况下则匹配每一行的结尾

例如:把字符串中的开头和结尾替换成#(可以理解为插入,或者把开头和结尾的空字符替换成#

console.log(`hello`.replace(/^|$/g, `#`));
// #hello#

多行匹配时每一行都有开头和结尾,需要用  gm 修饰符

console.log(`I\nLOVE\nYOU`.replace(/^|$/gm, `#`));
// #I#
// #LOVE#
// #YOU#

注意:管道符 |  会使用惰性模式匹配,如果结尾不加g修饰符,会匹配到开头之后直接停止

2.2  \b 和 \B

\b(单词边界),具体就是\w和\W之间的空字符

例如:字符串 [LOVE], \b匹配到的就是 [ 和 L之间的空字符,以及 E 和 ] 之间的空字符

let regex = /\b/g;
let string = `[regex] Test_1.js`;
console.log(string.replace(regex, `#`));
// [#regex#] #Test_1#.#js#

2.3 (?=p)和(?!p)

(?=p)—— 表示p前面的位置   ex:(?=a)表示a前面的位置

let regex = /(?=l)/g;
console.log('hello'.replace(regex, '#'));
// he#l#lo

(?!p)——表示的是(?=p)的反面意思,即除了p前面的位置以外的所有位置

let regex = /(?!l)/g;
console.log('hello'.replace(regex, '#'));
// #h#ell#o#

二者的学名分别是 positive lookahead(正向先行断言) 和 negetive lookahead(负向先行断言)

ES6中还支持(?<=p)和(?<!p),宜用例子去理解

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值