前端的正则表达式详解
定义
正则表达式 Regular Expression
,由普通字符、元字符和修饰符组成,描述了一种字符串匹配的模式 pattern
,通常被用来检索、取出、替换那些符合模式的文本。
符号
普通字符
字符 | 含义 |
---|---|
[abc][A-Z] | 匹配括号中任意一个字符 |
[^abc] | 匹配非括号中任意一个字符 |
\d | 匹配数字字符,等价于[0-9] |
\w | 匹配字母、数字、下划线,等价于[A-Za-z0-9_] |
\b | 匹配单词边界 |
\s | 匹配不可见字符,等价于[\f\n\r\t\v] |
\f\n\r\t\v | 匹配换页、换行、回车、制表、垂直制表符 |
可以用这里需要注意的是,\D
来表示对\d
取反,其余同理。
[^]
取反只对任意一个字符有效,如果要匹配多个字符例如非ab且非ac的话是不能用[^ab|ac]来表述的,只能把每个字符拆开表述 [^a][^b]|[^a][^c]
或者使用否定断言 (?!ab)(?!ac)
。元字符
元字符是一些有特殊含义的字符,简单点说就是在被匹配时需要在前加一个
\
转义的字符。字符 | 含义 |
---|---|
. | 匹配非换行符,等价于[^\n\r] |
^ | 匹配表达式的开始位置 |
$ | 匹配表达式的结束位置 |
| | 匹配左边或右边 |
()[]{} |
*+?
亦属于限定符,将在限定符中讲解。限定符
限定符用来指定正则表达式的某个
pattern
被匹配次数。字符 | 含义 |
---|---|
* | 匹配0或多次,等价于{0,} |
+ | 匹配1或多次,等价于{1,} |
? | 匹配0或1次,等价于{0,1} |
{n} | 匹配n次 |
{n,} | 匹配至少n次 |
{n,m} | 匹配至少n次至多m次 |
限定符都是贪婪的,会尽可能多的匹配,?
如果跟在限定符后属于非贪婪模式,将实现尽可能少的匹配。
'1 23'.match(/\d{1,2}/g);
// ['1', '23']
'1 23'.match(/\d{1,2}?/g);
// ['1', '2', '3']
获取匹配
用圆括号
()
可以分组捕获 pattern
,多个被获取的匹配可以用$1...$9来得到。/(\w+)\s(\w+)/.test('Brown Bear');
console.log(RegExp.$1);
// Brown
console.log(RegExp.$2);
// Bear
反向引用符 反向引用允许在正则表达式内部引用之前分组捕获的文本,原则是由外向内、由左向右。
字符 | 含义 |
---|---|
\num | num表示所引用分组的编号 |
// 检查日期格式
/\d{4}([/\-.])\d{2}\1\d{2}/.test('1990/08/02')// 检查成对标签
/<(\w+)>.*?<\/\1>/.test('bear')
非获取匹配符 当不需要得到这组内容时,可以用非获取匹配符来实现。
字符 | 含义 |
---|---|
(?:pattern) | |
(?=pattern) | 断言,预查匹配pattern的 |
(?!pattern) | 否定断言,预查不匹配pattern的 |
/Bear(?=082)/.test('Bear082') // true
/Bear(?=082)/.test('Bear0802') // false/Bear(?!082)/.test('Bear082') // false
/Bear(?!082)/.test('Bear0802') // true
这里需要注意的是,
JavaScript
起初并不支持反向断言 (?<=)
和反向否定断言 (?,虽然后续在 ES2018
中补全了这一特性,但这并不会被 babel
或 polyfill
转换,所以需要谨慎使用(个人建议暂时弃用)。
【前端的正则表达式详解】
文章图片
修饰符
修饰符用于指定额外的匹配策略,位于正则表达式之外。
/pattern/flags
修饰符
含义
实例
i
忽略大小写
'Bear'.match(/bear/i)
g
全局匹配
'bear bear'.match(/bear/g)
m
多行匹配,使边界符 ^
和 $
匹配每一行
'bear\nbear'.match(/^bear/gm)
s( ES2018
新增)
允许.
匹配换行符\n\r
'bear\nbear'.match(/bear./s)
s
修饰符出现之前一般用 /s/S
来替代匹配任何字符,ES
新特性另外还新增了 u
和 y
修饰符,由于使用场景相当之少,这里就不花篇幅介绍了。
属性
source
属性返回当前正则表达式的字符串,该字符串不会包含两边的斜杠以及任何的标志字符。
const reg = /bear/g;
reg.source;
// bear
大家熟知的 underscore
和 lodash
的 template 方法源码中有这么一段经典代码:
export default _.templateSettings = {
evaluate: //g,
interpolate: //g,
escape: //g
};
var matcher = RegExp([
(settings.escape || noMatch).source,
(settings.interpolate || noMatch).source,
(settings.evaluate || noMatch).source
].join('|') + '|$', 'g');
- evaluate对应表达式
- interpolate对应插入值
- escape对应转义值
当需要将这三种正则合并成一种使其都能匹配到时,source
的巧妙用法就能帮助代码简洁易懂许多。
方法
String.prototype
- replace
- match 返回一个字符串匹配正则表达式的结果,与
exec
类似但不如其强大
- search 返回搜索匹配的索引
鉴于 replace
的高频使用次数及强大功能,这里额外花些篇幅讲解下。
参数
含义
regexp | substr
被替换的正则表达式匹配的文本或字符串,字符串格式时仅第一个匹配项会被替换
newSubStr | function
用于替换的字符串值或生成替换文本的函数
用于替换的字符串newSubStr中 $
字符具有特定的含义:
字符
含义
$$
$
$&
匹配的文本
$`
匹配的文本的左边的文本
$'
匹配的文本的右边的文本
$1...$99
匹配的第1到99个被捕获的文本,如果不存在该分组则直接沿用字面量
'Brown Bear'.replace(/(\w+)\s(\w+)/, '$2 $1');
// 'Bear Brown'
'Brown Bear'.replace(/(\w+)\s(\w+)/, '$3 $2 $1');
// '$3 Bear Brown'
RegExp.prototype
- test 查看正则表达式与指定的字符串是否匹配,返回
true
或 false
- exec 在一个指定字符串中执行一个搜索匹配,返回一个结果数组或
null
常用案例
手机号加密
'13012345678'.replace(/(\d{3})\d{4}/, '$1****');
文章图片
前端加密属于掩耳盗铃,还是要区分场合使用,千万不要因为学到了就装X(我来做!一行正则搞定的事情!)。
千位分隔符
'12345678'.replace(/(\d{1,3})(?=(\d{3})+$)/g, '$&,');
这里其实还有一种更高大上的实现方式:
(12345678).toLocaleString();
可能有细心的同学要问,如果分隔符是 .
怎么办呢,这个方法还能用吗?回答是当然,可以通过第一个参数区域locales来支持,这里就不赘述了。
文章图片
验证密码复杂度
// 要求密码中必须包含大小写字母、数字,至少8个字符至多16个字符
/^(?:(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])).{8,16}$/.test('Bear0802');
文章图片
可视化工具
https://tooltt.com/regulex/
- 支持正则可视化
- 支持导出为图片,方便分享、留存
文章图片
结语
正则表达式需要强大的基本功作为支撑,理解吃透它并不容易,真正用到它时,先不要忙于生搬硬套,罗列出所有场景并结合可视化工具,写出符合自己需求的正则表达式。
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 其实,这就是你成熟的样子了
- 2017-06-25
- 一个新的时代即将诞生
- 你看到的,都是别人想让你看到的样子
- 说走就走的旅程
- 为你,千千万万遍|为你,千千万万遍 读追风筝的人有感
- 初生黄瓜,孕育希望
- 重生
- 我身边的感动|我身边的感动 2011-9-22 10:56
- 你的创作,值得更多——YOYOW如何用区块链让内容变现更有效()