《前端竹节》(2)【正则表达式】
正则表达式在前端开发中,对于字符串处理任务来说,绝对是一件可以祭出的大杀器。同时对于前端开发人员来说也是一项基本技能,但若只是停留在能看懂,知道去哪查的阶段,那距离得心应手地运用差的可能不止一步两步。
行业总习惯通过工作年限,来粗略估计一个工程师的能力与水平,因为随着时间的延展总觉得会积累下些许经验。但年限这种间接的衡量指标太因人而异,太难得到及时的正反馈。后来慢慢地发现,只有基于自己独立地思考,总结并输出才会感到真实的成长,就像竹子长一段就得生一个节。一. 正则使用分类
正则表达式(后文简称为“正则”)可划分出两种使用方式:
通过正则字面量与通过RegExp构造函数创建出来的正则对象,在不考虑访问正则对象属性的情况下,是等价的。如果需访问正则对象的属性,需通过RegExp初始化正则实例。正则表达式字面量
/正则匹配模式/[修饰符]
字符串对象内置了一些与使用正则表达式相关的方法,这些方法的入参就是所需的正则表达式字面量- match : 返回一个数组或者在未匹配到时返回null
- search : 返回匹配到的位置索引,或者在失败时返回-1
- replace : 使用替换字符串替换掉匹配到的子字符串
- split : 一个使用正则表达式或者一个固定字符串分隔一个字符串,并将分隔后的子字符串存储到数组中
RegExp构造的正则表达式对象
new RegExp("正则匹配模式"[, 修饰符])
通过正则构造函数实例化的正则对象,同样也具有类似的方法- exec : 返回一个数组或者在未匹配到时返回null
- test : 匹配到返回true否则false
二. 正则的使用(持续更新)
当匹配到时,
exec
和match
返回结果的不同字符串的match方法,当正则表达式按照字面量传参时,返回匹配到字符串的数组
// 字符串的match方法 var str = "cdbbdbsbz" var ret1 = str.match(/d(b+)d/g) console.log(ret1) // ["dbbd"]
当传参为正则对象时,返回值与exec方法相同。
正则对象的exec方法,返回从索引值处开始首次匹配到结果的字符串数组,数组的第一个元素为结果字符串,若匹配模式中存在括号,则括号中的子模式在本次匹配中得到的字符串,依次排列在结果数组中。与此同时,该数组对象还附带了一些相关的属性。
// 正则对象的exec方法 var regExp = new RegExp(/d(b+)d/, 'g') var ret2 = regExp.exec(str) console.log(ret2) // ["dbbd", "bb", index: 1, input: "cdbbdbsbz", groups: undefined]
对象 属性 描述 例子中对应的值 retArray 匹配到的字符串,和所有被记住的字符串 ["dbbd", "bb"] index 本次匹配结果,开始的索引值 1 input 初始字符串 "cdbbdbsbz" [0] 本次匹配到的字符串 "dbbd" regExp lastIndex 下一个匹配的索引值 5 source 匹配模式的文本 "d(b+)d"
使用括号的子字符串匹配(组匹配)
拿上例的匹配模式来看/d(b+)d/g
,括号中匹配到的子字符串,会被记录在数组元素[1],...,[n]中,且保存数量可以是无限的。除了通过js直接使用外,还可以这样使用:var name = "John Tom" var newName = name.replace(/(\w+)\s(\w+)/, "$2 $1") console.log(newName) // Tom John
正则表达式修饰符
- g:全局搜索
- i:不区分大小写搜索
- m:多行搜索,
^
和$
匹配的开始或结束输入字符串中的每一行,而非整个输入字符串 - u:开启Unicode模式,用来正确处理大于
\uFFFF
的字符 - y:粘连匹配,类似全局搜索,但不同是其要求在
lastIndex
的位置发现匹配,而g
是从lastIndex
处开始搜索,也就是说粘连匹配y
模式中隐藏了头部匹配的标志^
。
具名组匹配
上面有讨论过组匹配的概念和用法,通过数组下标的方式使用总会带来些许不便,所以在ES2018中引入了具名组匹配,允许为每一个组匹配指定一个名字,以方便阅读和调用,来看例子:// 之前的组匹配 const RE_DATE = /(\d{4})-(\d{2})-(\d{2})/; const matchObj = RE_DATE.exec('1999-12-31'); const year = matchObj[1]; // 1999 const month = matchObj[2]; // 12 const day = matchObj[3]; // 31 // 使用具名组匹配 const RE_DATE = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/; const matchObj = RE_DATE.exec('1999-12-31'); const year = matchObj.groups.year; // 1999 const month = matchObj.groups.month; // 12 const day = matchObj.groups.day; // 31
三. 正则匹配模式
下表列出了在正则表达式中,可以利用的特殊字符的完整列表和描述
字符 | 含义 |
---|---|
/ | 1. 在非特殊字符前,表示特殊用途; 2. 在特殊字符前,转义为字面量;3. 在new RegExp("pattern") 中需将 进行转义。 |
^ | 匹配输入的开始。若设置多行匹配,则也匹配换行符后紧跟的位置 |
$ | 匹配输入的结束。若设置多行匹配,则也匹配换行符前的位置。 |
* | 匹配前一个表达式0次或多次。等价于 {0,} |
+ | 匹配前面一个表达式1次或者多次。等价于 {1,} |
? | 1. 匹配前面一个表达式0次或者1次。等价于 {0,1};2. 如果紧跟在任何量词 *、 +、? 或 {} 的后面,将会使量词变为非贪婪的(匹配尽量少的字符),和缺省使用的贪婪模式(匹配尽可能多的字符)正好相反。 |
. | 匹配除换行符之外的任何单个字符 |
(x) | 匹配 x 并且记住匹配项 |
(?:x) | 匹配 x 但是不记住匹配项(非捕获括号) |
x(?=y) | 匹配 x 仅仅当x 后面跟着y (正向肯定查找) |
x(?!y) | 匹配 x 仅仅当x 后面不跟着y (正向否定查找) |
{n} | 匹配了前面一个字符刚好发生了n次(n为正整数) |
{n,m} | 匹配前面的字符至少n次,最多m次 |
[xyz] | 表示字符集合,匹配方括号的中任意字符 |
[^xyz] | 表示一个反向字符集,匹配没在方括号的中任意字符 |
[\b] | 匹配一个退格(U+0008) |
\b | 匹配一个词的边界 |
\b | 匹配一个非单词边界 |
\cX | 当X是处于A到Z之间的字符的时候,匹配字符串中的一个控制符 |
\d | 匹配一个数字,等价于[0-9] |
\d | 匹配一个非数字字符,等价于[^0-9] |
\f | 匹配一个换页符 |
\n | 匹配一个换行符 |
\r | 匹配一个回车符 |
\s | 匹配一个空白字符,包括空格、制表符、换页符和换行符 |
\s | 匹配一个非空白字符 |
\t | 匹配一个水平制表符 |
\v | 匹配一个垂直制表符 |
\w | 匹配一个单字字符(字母、数字或者下划线) |
\w | 匹配一个非单字字符 |
\n | 它返回最后的第n个子捕获匹配的子字符串(捕获的数目以左括号计数) |
\0 | 匹配 NULL (U+0000) 字符,不要在这后面跟其它小数,因为 0<digits> 是一个八进制转义序列。 |