前言:在常规的开发中正则或许是不需要完全掌握,但是随着技术的深入挖掘或者说要深入某一个框架源码
解析在或者寻找一些日常处理字符串
的更好的处理方式,那么正则表达式可以说是必不可少
的。下面就随着我开始从从浅到深一步一步的揭开正则表达式的神秘面纱。
开始之前我们需要掌握几个概念
正则表达式有几种呈现方式?
元字符是什么?常用的有哪些?
常用的修饰符都有哪些?
什么是正则的贪婪模式和非贪婪模式
- ...
正则表达式呈现方式
我们可以用一个例子来看一下以下两个的方式有何不同。
🌰 【文本中是否含有test的字段】
:
let str = 'this is test';
console.log(str.indexOf('test') !== -1) // true
console.log(str.includes('test')) // true
简写
//
: 两个斜杠它的含义其实跟数组[]
类似都属于简写。举几个简单字的例子看一下:
🌰 正则:
// 文本中是否含有test的字段
let str = 'this is test';
let res = /test/
console.log(res.test(str)) // true
构造函数
new RegExp(pattern[, flags])
:构造函数的方式进行创建,应用场景不是很多,但是支持动态传参。对于一些需要动态配置规则的场景还是很有帮助的。
🌰 正则:
// 找出含有test的文本
let str = 'this is test';
function foo(r, s) {
const re = new RegExp(r)
return re.test(s)
}
let res1 = foo('test', str); // true
let res2 = foo('test1', str); // false
元字符
元字符就是拥有特定功能的特殊字符,大部分需要加反斜杠进行标识,以便于跟普通字符进行区分,而少数的元字符则需要加上反斜杠,以便于转义为普通字符使用。
常见的元字符列表
字符 | 描述 |
---|---|
\ | 将下一个字符标记为一个特殊字符、或一个原义字符、或一个 向后引用、或一个八进制转义符。例如,'n' 匹配字符 "n"。'\n' 匹配一个换行符。序列 '\' 匹配 "\" 而 "(" 则匹配 "("。 |
^ | 匹配输入字符串的开始位置。如果设置了 RegExp 对象的 Multiline 属性,^ 也匹配 '\n' 或 '\r' 之后的位置。 |
$ | 匹配输入字符串的结束位置。如果设置了RegExp 对象的 Multiline 属性,$ 也匹配 '\n' 或 '\r' 之前的位置。 |
* | 匹配前面的子表达式零次或多次。例如,zo 能匹配 "z" 以及 "zoo"。 等价于{0,}。 |
+ | 匹配前面的子表达式一次或多次。例如,'zo+' 能匹配 "zo" 以及 "zoo",但不能匹配 "z"。+ 等价于 {1,}。 |
? | 匹配前面的子表达式零次或一次。例如,"do(es)?" 可以匹配 "do" 或 "does" 。? 等价于 {0,1}。 |
{n} | n 是一个非负整数。匹配确定的 n 次。例如,'o{2}' 不能匹配 "Bob" 中的 'o',但是能匹配 "food" 中的两个 o。 |
{n,} | n 是一个非负整数。至少匹配n 次。例如,'o{2,}' 不能匹配 "Bob" 中的 'o',但能匹配 "foooood" 中的所有 o。'o{1,}' 等价于 'o+'。'o{0,}' 则等价于 'o*'。 |
{n,m} | m 和 n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。例如,"o{1,3}" 将匹配 "fooooood" 中的前三个 o。'o{0,1}' 等价于 'o?'。请注意在逗号和两个数之间不能有空格。 |
. | 匹配除换行符(\n、\r)之外的任何单个字符。要匹配包括 '\n' 在内的任何字符 |
说一千道一万还不如来几个例子看看元字符如何使用
🌰 栗子:
找到字符串的特殊字符
let str = '.-&*'
let re = /[\.\-\&\*]+/
console.log(re.test(str)) // true
利用转义字符进行匹配特殊的字符比如说:\-
、\&
、\.
等等跟原生的JavaScript的转义原理一致。
上图:
🌰 栗子:
判断字符串是否以数字开头字母结尾
let str = 'abc123'
let re = /^[a-z]+[0-9]+$/;
re.test(str) // true
讲解: ^
是以xxx开始,&
是以xxx结束,在[a-z]
表示在a-z字符中随便一个,+
一次或者多次。
上图:
🌰 栗子:
替换日期的格式
let str = '2019-10-1'
let re = /(\d+)\-(\d+)\-(\d+)/;
let result = str.replace(re, `$1年$2月$3日`);
console.log(result) // 2019年10月1日
讲解: 利用元字符()
分组的概念可以拿到匹配的分组名称,然后进行本地替换。
上图:
🌰 栗子:
匹配16进制的颜色值
let str = '#ffbbad #Fc01DF #FFF #ffE'
let regex = /#[0-9a-zA-Z]{3,6}/g;
console.log(str.match(regex));
讲解:找到16进制符的规律,使用{3,6}
的形式进行匹配 最少3
次,最多6
次 。
上图:
以上是对元字符怎么使用有了简单的介绍,想要掌握的更加详细的话还需要多看多练多谢。下面看一下常用的修饰符。
常用的修饰符
g
:全局模式,表示查找字符串的全部内容,而不是找到一个匹配的内容就结束。
🌰 栗子:
// 找出含有test的文本
let str = 'this is test test';
str.match(/test/); // 查询第一次匹配项
str.match(/test/g);// 查找所有的匹配项 ['test','test']
关于字符串的match方法,请自行查阅。
i
:不区分大小写,表示在查询匹配时忽略pattern和字符串的大小写。
🌰 栗子:
// 找出含有test的文本
let str = 'this is TEST TEST';
str.match(/test/); // null
str.match(/test/i);// 查询到第一个TEST,
str.match(/test/ig);// 全局查询不分大小写的test字符串
m
:多行模式,表示在查找到一行文本末尾时会继续查找。
需要注意的是:m的多行模式会修改^
和$
的行为,默认情况下^
和$
匹配字符串的开始处和结尾处,加上m
修饰符以后,^
和$
还会匹配行首和行尾,即^
和$
会识别换行符\n
。
PS: 都属于元字符
会在之后面讲到。
^
: 匹配输入字符串的开始位置。$
:匹配输入字符串的结束位置。
🌰 栗子:
// 找出含有test的文本
let str = 'this is test\n'
/test$/.test(str) // false
/test$/m.test(str) // true
y
:粘附模式,表示只查找从lastIndex开始及之后的字符串。
大白话解释:y修饰符
其实和g修饰符
差类似,为什么说类似
呢?因为g修饰符
只要剩余有位置存在
就行,而y修饰符
必须从剩余的第一个位置
开始,这也就是粘连的含义。
🌰 栗子:
// 找出含有a的文本
let str = 'aaa_aa_a'
let r1 = /a+/g;
let r2 = /a+/y;
r1.exec(str) // ['aaa']
r2.exec(str) // ['aaa']
r1.exec(str) // ['aa']
r2.exec(str) // null
解释:一个使用g修饰符
,另一个使用y修饰符
。这两个正则表达式各执行了两次,第一次执行的时候,两者行为相同,剩余字符串都是_aa_a
。由于g修饰
没有位置要求,所以第二次执行会返回结果,而y修饰符
要求匹配必须从头部开始,所以返回null
。更多的细节
m
:Unicode 模式,启用 Unicode 匹配。
大白话解释:会正确处理四个字节的 UTF-16 编码。更多的细节
🌰 栗子:
let str = '𠮷';
/^.$/.test(str) // false
/^.$/u.test(str) // true
s
:dotAll 模式,表示元字符.匹配任何字符(包括\n 或\r)。
大白话解释: 其实在元字符串的.
可以代表任意的字符,但是不包括\n \r
等终止符,s修饰符
就是解决这个使用的。
🌰 栗子:
let str = 'hello\nworld'
/hello.world/.test(str) // false
/hello.world/s.test(str) // true
正则的贪婪模式和非贪婪模式
在说贪婪模式和非贪婪模式的话 需要先掌握一下什么是量词
,如下图:
其实量词属于元字符的一种,你不必在意这么多的新名词,但是至少你要知道它的作用灵活掌握。
举一个例子看一下什么是贪婪模式和非贪婪摸模式:
🌰 栗子:
贪婪模式
var regex = /\d{2,5}/g;
var string = "123 1234 12345 123456";
console.log(string.match(regex)); // ["123", "1234", "12345", "12345"]
上图:
非贪婪模式
var regex = /\d{2,5}?/g;
var string = "123 1234 12345 123456";
console.log(string.match(regex)); // ["12", "12", "34", "12", "34", "12", "34", "56"]
上图:
发现什么不同了吗?对了 就是多了一个?
只要在量词后面加上?
表示的只要满足要求了 就不在往下匹配了。非贪婪模式 又称惰性量词
,
具体的可以参考老姚的正则书 里面很细致的说明了正则的一些概念和方法论、建议时常读一读写一写。
最后
其实关于正则的概念有很多、我这里只是帮助你在复杂的正则世界里铺垫了一块转,入入门。之后还需要你自己去探索,有时间不妨看看我推荐的老姚的正则表达书,如果你也需要其他的书籍来夯实你的基础也可以下载我整理的书籍列表,来免费下载。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。