前端进阶必须知道的正则表达式知识 - Go语言中文社区

前端进阶必须知道的正则表达式知识


(给前端大全加星标,提升前端技能

作者:前端下午茶 公号 /  SHERlocked93

在实际做项目过程中会经常遇到需要验证的情况,这时候如果对正则表达式不够了解,就需要经常去网上找,显得low,为了能够自己手写正则,在下花功夫做了一些笔记,并且用这些知识做了一个正则的代码库(链接见文末),方便平时自己使用。

声明:

  1. ES9代表ES2018,如果特性后加了ES9,那么代表是ES2018中新增的特性

感兴趣的同学可以加文末的微信群,一起讨论吧~

1. 简介

正则表达式(Regular Expression) 是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个规则字符串,这个规则字符串用来表达对字符串的一种过滤逻辑。

简单来说就是:按照某种规则去匹配符合条件的字符串。正则表达式的规则是 / pattern /flags

可以使用字面量形式或者new的方式来创建正则表达式

// 使用直接字面量创建 ,推荐使用,性能更好,注意这里pattern不能为空,不然以为是注释	
var exp1 = /d/g	
// 使用RegExp对象创建	
var exp2 = new RegExp('d', 'g');

模式中使用的所有元字符都建议在之前加 转义,正则表达式中的元字符包括:

( [ {  ^ $ | ) ? * + . ] }

2. 内容

2.1 匹配模式

修饰符表示正则表达式的匹配模式

修饰符描述
i执行对大小写不敏感的匹配
g执行全局匹配,查找所有匹配而非在找到第一个匹配后停止
m执行多行匹配,会改变 ^和 $的行为
u可以匹配4字节的unicode编码
s (ES9)dotAll模式, .可以匹配换行符

加了u修饰符,会正确处理大于 uFFFF的unicode,比如4字节的? uD83DuDC2A

/^uD83D/.test('uD83DuDC2A')                //  true	
/^uD83D/u.test('uD83DuDC2A')               //  false

默认情况下, .可以匹配任意字符,除了换行符,且 .不能匹配Unicode字符,需要使用u选项启用Unicode模式才行。

ES2018引入了dotAll模式,通过s选项可以启用,这样, .就可以匹配换行符了。

/foo.bar/.test('foonbar');                 // false	
/foo.bar/s.test('foonbar');                 // true

2.2 类

使用 []来表达,用于查找某个范围内的字符

表达式描述
[abc]查找方括号之间的任何字符
[0-9]查找任何从 0 至 9 的数字

还有一些预定义类方便我们直接使用:

预定义类等价描述
s[tnx0Bfr]空格
S[^tnx0Bfr]非空格
d[0-9]数字
D[^0-9]非数字
w[a-zA-Z_0-9]单词字符 ( 字母、数字、下划线)
W[^a-zA-Z_0-9]非单词字符
.[^rn]任意字符,除了回车与换行外所有字符
fx0c cL匹配一个换页符
nx0a cJ匹配一个换行符
rx0d cM匹配一个回车符
tx09 cI匹配一个制表符
vx0b cK匹配一个垂直制表符
xxx
查找以八进制数 xxx 规定的字符
xdd
查找以十六进制数 dd 规定的字符
uxxxx
查找以十六进制数 xxxx 规定的 Unicode 字符

2.3 量词

量词表示匹配多少个目标对象,精确匹配长度使用 {}

量词等价描述
*{0,}匹配零个或多个n
+{1,}匹配至少一个 n 的字符串
?{0,1}匹配零个或一个n
{n}
匹配n次
{n,m}
匹配n到m次
{n,}
至少匹配n次

2.4 边界

边界描述
^以xx开始,在类 []中表示非
$以xx结束
b单词边界
B非单词边界

^匹配字符串开始位置,也就是位置0,如果设置了 RegExp 对象的 Multiline 属性 m^也匹配 'n' 或 'r' 之后的位置

$一般匹配字符串结束位置,如果设置了 RegExp 对象的 Multiline 属性 m$ 也匹配 'n' 或 'r' 之前的位置

b匹配一个单词边界,也就是指单词和空格间的位置,如 erb可以匹配"never" 中的 'er',但不能匹配 "verb" 中的 'er' B匹配非单词边界。如 erB能匹配 "verb" 中的 'er',但不能匹配 "never" 中的 'er'

2.5 分组

分组使用 (),作用是提取相匹配的字符串,使量词作用于分组 比如 hehe{3}是把 e匹配了3次而不是单词,如果希望作用于单词,可以使用分组 (hehe){3}

分组中使用 | 可以达到的效果 比如:T(oo|ii)m可以匹配 Toom 和 Tiim

`abToomhaTiimmm`.replace(/T(oo|ii)m/g, '-')                // ab-ha-mm

反向引用

使用 ()后可以使用 $1- $9等来匹配

'2018-02-11'.replace(/(d{4})-(d{2})-(d{2})/g, '$2/$3/$1')            //  02/11/2018

后向引用

n 表示后向引用, 1是指在正则表达式中,从左往右数第1个 ()中的内容;以此类推, 2表示第2个 ()表示整个表达式。

//匹配日期格式,表达式中的1代表重复(-|/|.)	
var rgx = /d{4}(-|/|.)d{1,2}1d{1,2}/	
rgx.test("2016-03-26")             // true	
rgx.test("2016-03.26")             // false

后向引用和反向引用的区别是:n只能用在表达式中,而 $n只能用在表达式之外的地方。

分组命名 (ES9)

ES2018 之前的分组是通过数字命名的:    

const pattern = /(d{4})-(d{2})-(d{2})/u;	
const result = pattern.exec('2018-10-25');	
console.log(result[0]); // 打印"2018-10-25"	
console.log(result[1]); // 打印"2018"	
console.log(result[2]); // 打印"10"	
console.log(result[3]); // 打印"25"

现在可以通过指定分组的名称,增加代码可读性,便于维护:

const pattern = /(?<year>d{4})-(?<month>d{2})-(?<day>d{2})/u;	
const result = pattern.exec('2018-10-25');	
console.log(result.groups.year);         // 打印"2018"	
console.log(result.groups.month);        // 打印"10"	
console.log(result.groups.day);          // 打印"25"

分组命名还可以和 String.prototype.replace方法结合:

const reDate = /(?<year>d{4})-(?<month>d{2})-(?<day>d{2})/;	
const d = '2018-10-25';	
const USADate = d.replace(reDate, '$<month>-$<day>-$<year>');	
console.log(USADate);                        // 10-25-2018

忽略分组

如果不希望捕获某些分组,在分组内加上 ?:即可 比如 (?:tom).(ok)那么这里 $1指的就是ok

前瞻

前瞻 Lookahead 是RegExp匹配到规则的时候,向后检查是否符合断言,后顾JS目前不支持 (ES2018已经支持)

名称正则描述
正向前瞻(?=)后面要有xx
负向前瞻(?!)后面不能有xx
'1a2bc*456v8'.replace(/w(?=d)/g, '-')        //  1-2bc*--6-8    匹配后面是数字的单词字符	
'1a2bc*456v8'.replace(/w(?!d)/g, '-')               //  -a---*45-v-    匹配后面不是数字的单词字符	
const pattern1 = /d+(?= dollars)/u;             // 正向前瞻,匹配字符串中紧跟着是dollars的数字	
const result1 = pattern1.exec('42 dollars');	
console.log(result1[0])                                    // 打印42	
const pattern2 = /d+(?! dollars)/u;           // 负向前瞻,匹配字符串中紧跟着的不是dollars的数字	
const result2 = pattern2.exec('42 pesos');	
console.log(result2[0]);                                     // 打印42

(?=exp)匹配一个位置,这个位置的右边能匹配表达式exp,注意这个表达式仅仅匹配一个位置,只是它对于这个位置的右边有要求,而右边的东西是不会被放进结果的,比如用 read(?=ing)去匹配"reading",结果是"read",而"ing"是不会放进结果的。

举个栗子,对密码应用以下限制:其长度必须介于 4 到 8 个字符之间,并且必须至少包含一个数字,正则是 /^(?=.*d).{4,8}$/

后顾 (ES9)

后顾 Lookbehind 是RegExp匹配到规则的时候,向前检查是否符合断言

名称正则描述
正向后顾(?<=)前面要有xx
负向后顾(?<!)前面不能有xx
const pattern1 = /(?<=$)d+/u;           // 正向后顾,匹配字符串中前面是$的数字	
const result1 = pattern1.exec('$42');	
console.log(result1[0]);             // 打印42	
const pattern2 = /(?<!$)d+/u;           // 负向后顾,匹配字符串中前面不是是$的数字	
const result2 = pattern2.exec('€42');	
console.log(result2[0]);                 // 打印42

2.6 贪婪模式 与 非贪婪模式

正则表达式在匹配的时候默认会尽可能多的匹配,叫贪婪模式。通过在限定符后加 ?可以进行非贪婪匹配 比如 d{3,6}默认会匹配6个数字而不是3个,在量词 {}后加一个 ?就可以修改成非贪婪模式,匹配3次

`12345678`.replace(/d{3,6}/, '-')                // -78	
`12345678`.replace(/d{3,6}?/, '-')                // -45678	
'abbbb'.replace(/ab+?/, '-')                //  -bbb

2.7 优先级

优先级从高到低:

  1. 转义 

  2. 括号 ()、 (?:)、 (?=)、 []

  3. 字符和位置

  4. 或 |

3. 常用属性与方法

3.1 RegExp构造函数属性

RegExp构造函数上也包含一些属性,这些属性适用于作用域中所有的正则表达式,并且基于所执行的最近一次正则表达式操作而变化,这些属性分别有一个长属性名和短属性名

长属性名短属性名描述
input$_返回执行规范表述查找的字符串。只读
lastMatch$&返回任何正则表达式搜索过程中的最后匹配的字符。只读
lastParen$+如果有的话,返回任何正则表达式查找过程中最后括的子(分组)匹配。只读
leftContext$返回被查找的字符串中从字符串开始位置到最后匹配之前的位置之间的字符。只读
rightContext$'返回被搜索的字符串中从最后一个匹配位置开始到字符串结尾之间的字符。只读

3.2 RegExp实例上的属性

属性描述
global是否全文搜索,默认 false,对应修饰符的 g,只读
ignoreCase是否大小写敏感,默认 false,对应修饰符 i,只读
multiline是否多行搜索,默认 false,对应修饰符 m,只读
flags返回修饰符,只读
lastIndex当前表达式匹配内容的最后一个字符的下一个位置
source正则表达式的文本字符串

3.3 常用方法

版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/VhWfR2u02Q/article/details/97578227
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。

  • 发表于 2021-12-12 04:24:39
  • 阅读 ( 728 )
  • 分类:前端

0 条评论

请先 登录 后评论

官方社群

GO教程

推荐文章

猜你喜欢