谈谈 JavaScript 的正则表达式
一、背景
最近在做 CMS 系统中不同身份登录用户的权限管理,涉及到对 api 路径的识别去判断是否放行。以前对正则表达式都是敬而远之,要用到的话都是直接复制粘贴现成网上的表达式,看也看不太懂,借这次机会熟悉下,不求钻的多深,但求有个整体的认知,满足我目前的简单需求即可。
二、介绍
正则表达式(Regular Expression)是一种用来匹配字符串的强有力的工具。
各个编程语言对正则表达式的支持标准有所差异,这里只以 JavaScript 为例。
三、用法
本文对 非捕获括号、正向肯定查找、正向否定查找 不做介绍。
1、匹配符
| 匹配符 | 可以匹配 | 
|---|---|
| Iamstring | Iamstring | 
| . | 一个任意字符 | 
| \d | 一个数字 | 
| \D | 一个非数字 | 
| [a-zA-Z] | 一个字母 | 
| [^a-zA-Z] | 一个非字母 | 
| \w | 一个字母、数字或者下划线 | 
| [0-9a-zA-Z_] | 同上 | 
| \s | 一个空格(还包括制表符、换页符和换行符) | 
| [\u4e00-\u9fa5] | 中文 | 
| A|B | A 或 B | 
| [ABC] | A 或 B 或 C | 
| [A-C] | 同上 | 
2、特殊符号
上面的匹配符可以搭配下表的符号,如 /[A-Z]{3}/:
如果遇到歧义可使用**括号 **(),如
/bo+/和/(bo)+/表达的意思不一样。
| 特殊符号 | 表示 | 放匹配符的前面 | 放匹配符的后面 | 备注 | 
|---|---|---|---|---|
| {n} | n个字符 | √ | ||
| {n,m} | n-m个字符 | √ | ||
| * | 0或多个字符 | √ | 等价于{0,} | |
| + | 至少一个字符 | √ | 等价于{1,} | |
| ? | 0或1个字符 | √ | 等价于{0,1} | |
| ^ | 表示行的开头 | √ | ||
| $ | 表示行的结束 | √ | ||
| \b | 表示单词的边界 | √ | √ | |
| \B | 表示单词的非边界 | √ | √ | |
如果上述特殊符号是普通字符的话,需要用
\转义,如[A-Z]?{3}不对而[A-Z]\?{3}可以正确匹配上 "D???"。
3、贪婪模式和懒惰模式
(1)如何设置?
JavaScript 的正则表达式默认为贪婪模式(匹配尽量多的字符)。
但如果在 *、 +、? 或 {} 的后面出现?,将会变为非贪婪的懒惰模式(匹配尽量少的字符)。
例如,对 "123abc" 应用 /\d+/ 将会返回 "123",如果使用 /\d+?/,那么就只会匹配到 "1"。
(2)有何区别?

上图里有个术语叫回溯,会影响到正则匹配字符串的性能,在平时写正则的时候需要注意,详细请看下文的三、性能问题
注:java 的正则里还有一种模式叫
独占模式,貌似 JS 里没有(待求证)。
4、JavaScript 里使用
(1)创建和 function
// *** 创建正则表达式 ***
// 方法一:/正则表达式主体/修饰符(可选)
var reg1 = /\d/;
// 若 RegExp 是全局模式
// var reg1 = /\d/g;
// 方法二:new RegExp('正则表达式')
// 注意:不用添加/***/,且由于是字符串,所以需要考虑转义!
// var reg2 = new RegExp("\\d");
// 若 RegExp 是全局模式
// var reg2 = new RegExp("\\d",'g');
var string = '你好 123 123 js'
// *** RegExp 的方法 - test() exec() ***
console.log(reg1.test(string));  // true or false
console.log(reg1.exec(string));  // [ '1', index: 3, input: '你好 123 123 js' ]
console.log(reg1.exec(string));  // [ '1', index: 3, input: '你好 123 123 js' ] (跟上面一样)
// 若 RegExp 是全局模式
console.log(reg1.exec(string));  // [ '1', index: 3, input: '你好 123 123 js' ]
console.log(reg1.exec(string));  // [ '2', index: 4, input: '你好 123 123 js' ]
console.log(reg1.exec(string));  // [ '3', index: 5, input: '你好 123 123 js' ]
console.log(reg1.exec(string));  // [ '1', index: 7, input: '你好 123 123 js' ]
console.log(reg1.exec(string));  // [ '2', index: 8, input: '你好 123 123 js' ]
console.log(reg1.exec(string));  // [ '3', index: 9, input: '你好 123 123 js' ]
console.log(reg1.exec(string));  // null
console.log(reg1.exec(string));  // [[ '1', index: 3, input: '你好 123 123 js' ]
// *** String 的方法 - search() match() replace() split()  ***
console.log(string.search(reg1));   // 返回第一个匹配的下标,没有即是 -1 
console.log(string.match(reg1));    // [ '1', index: 3, input: '你好 123 123 js' ] (跟RegExp.exec()一样)
// 若 RegExp 是全局模式
console.log(string.match(reg1));    // [ '1', '2', '3', '1', '2', '3' ]
console.log(string.replace(reg1,'替换'));   // "你好 替换23 123 js"
// 若 RegExp 是全局模式
console.log(string.replace(reg1,'$2-$1'));   // "你好 替换替换替换 替换替换替换 js" 
console.log(string.split(reg1));    // [ '你好 ', '', '', ' ', '', '', ' js' ]
除了
g表示全局模式,还有i表示忽略大小写,m表示执行多行匹配。
(2)分组
用捕获括号() 可以分组,受影响的是 match()、split()、replace() 方法。
var string = '010-12345'
// 无()
var reg1 = /^\d{3}-\d{3,8}$/;
// 有()
var reg2 = /^(\d{3})-(\d{3,8})$/;
// match()
console.log(string.match(reg1));
// [ '010-12345', index: 0, input: '010-12345' ]
console.log(string.match(reg2));
// [ '010-12345', '010', '12345', index: 0, input: '010-12345' ]
// split()
console.log(string.split(reg1));
// [ '', '' ]
console.log(string.split(reg2));
// [ '', '010', '12345', '' ]
// replace() - 注意 $1、$2 的含义
console.log(string.replace(reg1,'替换'));
console.log(string.replace(reg2,'$2-$1'));	// 12345-010
三、性能问题
首先,实现正则表达式引擎有两种方式:DFA 自动机(Deterministic Final Automata 确定型有穷自动机)和 NFA 自动机(Non deterministic Finite Automaton 不确定型有穷自动机)。
对于这两种自动机,他们有各自的区别,这里并不打算深入将它们的原理。简单地说,DFA 自动机的时间复杂度是线性的,更加简单稳定,但是功能有限。而 NFA 的时间复杂度比较不稳定,有时候很好,有时候不怎么好,好不好取决于你写的正则表达式,但是胜在功能更加强大。
JS 与大多数主流语言的正则引擎选用的都是 NFA。
但需要注意的是,这种正则表达式引擎在进行字符匹配时会发生回溯(backtracking)。而一旦发生回溯,那其消耗的时间就会变得很长,有可能是几分钟,也有可能是几个小时,时间长短取决于回溯的次数和复杂度。
这里有两篇关于 JAVA 中遭遇到由于正则表达式的糟糕性能导致上线后服务器 CPU 飙到 100% 的血的经验地分享:
https://zhuanlan.zhihu.com/p/38278481
http://www.cnblogs.com/study-everyday/p/7426862.html
所以,我们更要在平时写正则表达式的时候,更加注重性能,避免回溯机制带来的隐患。我们可以用 https://regex101.com/ 来测试下match 的时间如何。
四、推荐工具
1、在线匹配
2、查看正则表达式的具体解析过程
五、参考资料:
1、MDN教程
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Regular_Expressions
2、廖雪峰教程
谈谈 JavaScript 的正则表达式的更多相关文章
- 详解Javascript中正则表达式的使用
		正则表达式用来处理字符串特别好用,在JavaScript中能用到正则表达式的地方有很多,本文对正则表达式基础知识和Javascript中正则表达式的使用做一个总结. 第一部分简单列举了正则表达式在Ja ... 
- javascript类型系统——正则表达式RegExp类型
		× 目录 [1]对象 [2]实例属性 [3]静态属性[4]实例方法 前面的话 前面已经介绍过javascript中正则表达式的基础语法.javascript的RegExp类表示正则表达式,String ... 
- JavaScript正则表达式详解(二)JavaScript中正则表达式函数详解
		二.JavaScript中正则表达式函数详解(exec, test, match, replace, search, split) 1.使用正则表达式的方法去匹配查找字符串 1.1. exec方法详解 ... 
- javascript中正则表达式的基础语法
		× 目录 [1]定义 [2]特点 [3]元字符[4]转义字符[5]字符组[6]量词[7]括号[8]选择[9]断言[10]模式[11]优先级[12]局限性 前面的话 正则表达式在人们的印象中可能是一堆无 ... 
- 深入浅出的javascript的正则表达式学习教程
		深入浅出的javascript的正则表达式学习教程 阅读目录 了解正则表达式的方法 了解正则中的普通字符 了解正则中的方括号[]的含义 理解javascript中的元字符 RegExp特殊字符中的需要 ... 
- JavaScript验证正则表达式大全
		JavaScript验证正则表达式大全,搜集最全的JavaScript验证正则表达式,开始查看吧,这里的都是正则表达式的例子,具体和函数结合的使用方法,还请查看下篇文章<JavaScript使用 ... 
- 如何使用JavaScript和正则表达式进行数据验证
		利用客户端JavaScript的优势,JavaScript中的正则表达式可以简化数据验证的工作,下面与大家分享下如何使用JavaScript和正则表达式进行数据验证,感兴趣的朋友可以参考下哈 数据验证 ... 
- JavaScript常用正则表达式与应用(一)
		JavaScript的String类和RegExp对象类都定义了相关方法使用正则表达式进行模式匹配,本文将以连载方式介绍JavaScript常用正则表达式与相关应用,欢迎交流 本节是连载一,首先介绍J ... 
- javascript基础-正则表达式
		概述 正则表达式被用来检索.替换那些符合某个模式的文本 标准正则表达式语法 javascript对正则表达式的支持 替代写法 逆向环视 //需求:替换mpre.cnsuning.com为${pre}, ... 
随机推荐
- Sql Server数据库之identity(自增)
			一.identity的基本用法 1.identity的含义: identity表示该字段的值会自动更新,通常情况下,不允许直接修改identity修饰的字段,否则编译会报错 2.基本语法 列名 数据 ... 
- ubuntu 从零安装tf-serving环境和opencv
			参考官网:https://www.tensorflow.org/serving/setup 首先是安装gprc: pip install grpcio 然后发现没有安装pip,报错:sudo: pip ... 
- R语言-图的要素颜色
			1.设置图形要素的颜色 Plot函数中,使用col=参数来决定要素的颜色 如果不指定plot type,颜色加在散点上,如果指定了plot type,例如line,则颜色加在线上 其它函数,例如bar ... 
- html2canvas
			最近公司有个需求,实现html 页面元素转为png图像,这边用了html2canvas来实现.,这里记录一下,避免以后忘了~~ 官网链接: http://html2canvas.hertzen.com ... 
- Java 虚拟机概述
			虚拟机是一种抽象化的计算机,通过在实际的计算机上仿真模拟各种计算机功能来实现的.Java虚拟机有自己完善的硬体架构,如处理器.堆栈.寄存器等,还具有相应的指令系统.Java虚拟机屏蔽了与具体操作系统平 ... 
- git配置正确且权限已开但是pull或push提示无权限
			因为之前提示输入用户名和密码时输入错误,之后就一直权限认证失败.这种情况下在git bash中输入: git config --system --unset credential.helper 就会重 ... 
- UVA10600 次小生成树
			题目链接:https://vjudge.net/problem/UVA-10600 题意:叫我们求出最小生成树的边权之和 和次小生成树的边权之和. 思路:我们可以先求出最小生成树,这个不难,如果要求次 ... 
- SpriteKit  关于categoryBitMask   collisionBitMask   contactTestBitMask 遇到的一些问题
			手写copy一下官方解释 首先是categoryBitMask /** 定义了这个物理刚体是属于哪个类别的掩码 .在一个场景中的每个物理刚体可以分配给达到 32 不同的类别(参数 int bitmas ... 
- jquery 设置某div里面的内容为此div里面非img标签的内容
			$('#div_1').html($('#div_1').children().not("img")); 要注意 <div id="#div_1"> ... 
- 【转载】通过sql server 连接mysql
			http://www.cnblogs.com/goole/p/5291286.html 1.在SQL SERVER服务器上安装MYSQL ODBC驱动; 驱动下载地址:http://dev.mysql ... 
