一、背景


最近在做 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、在线匹配

http://tool.oschina.net/regex

2、查看正则表达式的具体解析过程

https://regexper.com

五、参考资料:


1、MDN教程

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Regular_Expressions

2、廖雪峰教程

https://www.liaoxuefeng.com/wiki/001434446689867b27157e896e74d51a89c25cc8b43bdb3000/001434499503920bb7b42ff6627420da2ceae4babf6c4f2000

谈谈 JavaScript 的正则表达式的更多相关文章

  1. 详解Javascript中正则表达式的使用

    正则表达式用来处理字符串特别好用,在JavaScript中能用到正则表达式的地方有很多,本文对正则表达式基础知识和Javascript中正则表达式的使用做一个总结. 第一部分简单列举了正则表达式在Ja ...

  2. javascript类型系统——正则表达式RegExp类型

    × 目录 [1]对象 [2]实例属性 [3]静态属性[4]实例方法 前面的话 前面已经介绍过javascript中正则表达式的基础语法.javascript的RegExp类表示正则表达式,String ...

  3. JavaScript正则表达式详解(二)JavaScript中正则表达式函数详解

    二.JavaScript中正则表达式函数详解(exec, test, match, replace, search, split) 1.使用正则表达式的方法去匹配查找字符串 1.1. exec方法详解 ...

  4. javascript中正则表达式的基础语法

    × 目录 [1]定义 [2]特点 [3]元字符[4]转义字符[5]字符组[6]量词[7]括号[8]选择[9]断言[10]模式[11]优先级[12]局限性 前面的话 正则表达式在人们的印象中可能是一堆无 ...

  5. 深入浅出的javascript的正则表达式学习教程

    深入浅出的javascript的正则表达式学习教程 阅读目录 了解正则表达式的方法 了解正则中的普通字符 了解正则中的方括号[]的含义 理解javascript中的元字符 RegExp特殊字符中的需要 ...

  6. JavaScript验证正则表达式大全

    JavaScript验证正则表达式大全,搜集最全的JavaScript验证正则表达式,开始查看吧,这里的都是正则表达式的例子,具体和函数结合的使用方法,还请查看下篇文章<JavaScript使用 ...

  7. 如何使用JavaScript和正则表达式进行数据验证

    利用客户端JavaScript的优势,JavaScript中的正则表达式可以简化数据验证的工作,下面与大家分享下如何使用JavaScript和正则表达式进行数据验证,感兴趣的朋友可以参考下哈 数据验证 ...

  8. JavaScript常用正则表达式与应用(一)

    JavaScript的String类和RegExp对象类都定义了相关方法使用正则表达式进行模式匹配,本文将以连载方式介绍JavaScript常用正则表达式与相关应用,欢迎交流 本节是连载一,首先介绍J ...

  9. javascript基础-正则表达式

    概述 正则表达式被用来检索.替换那些符合某个模式的文本 标准正则表达式语法 javascript对正则表达式的支持 替代写法 逆向环视 //需求:替换mpre.cnsuning.com为${pre}, ...

随机推荐

  1. Python设计模式 - UML - 用例图(Use Case Diagram)

    简介 用例图主要是从用户的角度出发对软件产品的功能及执行者进行描述的. 用例图是从需求分析到软件交付的第一步,图示化展示参与者与参与者之间.参与者与用例之间.用例与用例之间的关系,帮助开发人员更好的理 ...

  2. Centos7编译安装lnmp(nginx1.10 php7.0.2)

    我使用的是阿里云的服务器 Centos7 64位的版本 1. 连接服务器 这个是Xshell5的版本 安装好之后我们开始连接服务器 2. 安装nginx 首先安装nginx的依赖 yum instal ...

  3. iOS之Safari调试webView/H5页面

    之前做过混合开发,用的是JavaScriptCore+OC+UIWebView. Safari调试功能真的很有用,通过它可以轻松定位问题的所在,下面说说怎么调试. 开启Safari开发菜单 在Mac的 ...

  4. jdbcTemplate的简单介绍

    Spring JDBC抽象框架core包提供了JDBC模板类,其中JdbcTemplate是core包的核心类,所以其他模板类都是基于它封装完成的,JDBC模板类是第一种工作模式. JdbcTempl ...

  5. 优化linux,安装node环境

    就是这样我的心爱的云主机就被攻击了,反正我是很久没宠幸过她,肯定不是我去攻击人家,但是吧昨天就突然来了封邮件,小白一个查不出什么,用了 netsat -na显示所有连接到服务器的活跃的网络连接数,发现 ...

  6. node.js 使用 net 模块模拟 websocket 握手,进行数据传递。

    websocket 是一种让浏览器与服务器之间建立持久的连接,并能进行双向数据传输的一种协议. websocket 属性应用层协议,基于tcp传输协议,并复用http的握手通道. 一.如何进行webs ...

  7. 微软URLRewriter.dll的url重写在目标框架.Net Framework2.0、4.0和应用程序池经典模式、集成模式下的配置

    大家参考几篇园子里面的这篇文章: 文章1:微软URLRewriter.dll的url重写的简单使用 (讲解了使用UrlReWriter.dll的下载.web.config如何在目标框架2.0应用程序池 ...

  8. Eigen子矩阵操作

    1 子矩阵操作简介 子矩阵操作又称块操作,在矩阵运算中,子矩阵的提取和操作应用也十分广泛.因此Eigen中也提供了相关操作的方法.提取的子矩阵在操作过程中既可以用作左值也可以用作右值. 2 块操作的一 ...

  9. redis应用实践

    晚些时候自己总结,先贴出看到的一篇文章. https://www.cnblogs.com/NiceCui/p/7794659.html

  10. 目录命令(cd)

    cd 命令: // 描述: (Change Directory) 更改当前目录或显示当前目录的名称. 如果仅使用驱动器号(例如,cd C :),则cd将显示指定驱动器中当前目录的名称. 如果不带参数使 ...