作者:李一二

转发链接:https://mp.weixin.qq.com/s/PmzEbyFQ8FynIlXuUL0H-g

前言

有不少朋友都为写正则而头疼,不过笔者早已不为正则而烦恼了。本文分享一些我处理正则表达式的一些经验。全文分为正则利器,正则基础内容,正则进阶内容三个大块。

正则利器

首先推荐两个正则工具利器——分别是regex101(一个正则在线检验工具), Regulex(一个正则可视化工具)。这两个工具,可以大幅减小写正则的难度。(文章相关链接不可点击的,请点击文末的【阅读原文】阅读)做一个简单的演示, 比如常见的密码校验: 密码需要6位至18位,且只能为数字,字母,以及特殊字符,.*

先使用Regulex来在线编写正则。借助其将正则图形化的功能,我们很容易来修改调整自己的正则。

当通过Regulex工具写完正则过后,可以使用regex101来检查自己写的正则是否正确,以及匹配结果

当上面两个流程走通过后,意味着该正则是符合我们需求且正确无误的,就可以迁移入代码中啦。

手撕正则

关于正则的相关知识,我强烈推荐这篇文章《正则表达式30分钟入门教程》。接下来我会将正则内容与JavaScript穿插起来讲。

JS创建正则表达式

在JS里有两种创建正则表达式的方式,分别是字面量和调用RegExp对象的构造函数。使用一个正则表达式字面量,其由包含在斜杠之间的模式组成,如下所示:

var re = /ab+c/;

脚本加载后,正则表达式字面量就会被编译。当正则表达式保持不变时,使用此方法可获得更好的性能。

或者调用RegExp对象的构造函数,如下所示:

var re = new RegExp("ab+c");

在脚本运行过程中,用构造函数创建的正则表达式会被编译。 如果正则表达式将会改变,或者它将会从用户输入等来源中动态地产生,就需要使用构造函数来创建正则表达式。

总结一下,两种模式语法如下:

/pattern/flagsnew RegExp(pattern [, flags])RegExp(pattern [, flags])参数如下:pattern    正则表达式的文本。flags    如果指定,标志可以具有以下值的任意组合:    g    全局匹配;找到所有匹配,而不是在第一个匹配后停止        i    忽略大小写        m    多行; 将开始和结束字符(^和$)视为在多行上工作(也就是,分别匹配每一行的开始和结束(由  或  分割),而不只是只匹配整个输入字符串的最开始和最末尾处。        u    Unicode; 将模式视为Unicode序列点的序列        y    粘性匹配; 仅匹配目标字符串中此正则表达式的lastIndex属性指示的索引(并且不尝试从任何后续的索引匹配)。        s    dotAll模式,匹配任何字符(包括终止符 '')。

上面参数提到的全局匹配,粘性匹配的知识在本文后面将做细致的讲解。

基础知识

这里先了解一些基础的正则知识,不做过多的讲解。

常用元字符

常用限定符

常用的反义代码

JS里的一些正则函数

在 JavaScript中,正则表达式也是对象。这些模式被用于 RegExp 的 exec 和 test 方法, 以及 String 的 match、matchAll、replace、search 和 split 方法。

test

test() 方法执行一个检索,用来查看正则表达式与指定的字符串是否匹配。返回 true 或 false。

var str = 'hello world!';var result = /^hello/.test(str);console.log(result);// true

exec

exec() 方法在一个指定字符串中执行一个搜索匹配。返回一个结果数组或 null。

在设置了 global 或 sticky 标志位的情况下(如 /foo/g or /foo/y),JavaScript RegExp 对象是有状态的。他们会将上次成功匹配后的位置记录在 lastIndex 属性中 。使用此特性,exec() 可用来对单个字符串中的多次匹配结果进行逐条的遍历(包括捕获到的匹配),而相比之下, String.prototype.match() 只会返回匹配到的结果。

const regex1 = RegExp('foo*', 'g');const str1 = 'table football, foosball';let array1;while ((array1 = regex1.exec(str1)) !== null) {  console.log(`Found ${array1[0]}. Next starts at ${regex1.lastIndex}.`);  // expected output: "Found foo. Next starts at 9."  // expected output: "Found foo. Next starts at 19."}

上面提到了正则表达式的global和sticky 两种模式,这里我详细讲下这两种模式。

全局模式

global这里是指全局匹配——找到所有匹配,而不是在第一个匹配后停止。用前面提到的密码正则^[da-zA-Z,.*]{6,18}$来举个例子:

# 非全局模式var keyword = '2020myTestkeyword,';var reg = /^[da-zA-Z,.*]{6,18}$/i;   // (i , 忽略大小写)console.log(reg.lastIndex, reg.test(keyword)); // 输出0 trueconsole.log(reg.lastIndex, reg.test(keyword)); // 输出0 trueconsole.log(reg.lastIndex, reg.test(keyword)); // 输出0 trueconsole.log(reg.lastIndex, reg.test(keyword)); // 输出0 true---------------------# 全局模式var keyword = '2020myTestkeyword,';var regG = /^[da-zA-Z,.*]{6,18}$/ig;   // (i , 忽略大小写)console.log(regG.lastIndex, regG.test(keyword)); // 输出0 trueconsole.log(regG.lastIndex, regG.test(keyword)); // 输出18 falseconsole.log(regG.lastIndex, regG.test(keyword)); // 输出0 trueconsole.log(regG.lastIndex, regG.test(keyword)); // 输出18 false

上面的两段代码可以看到在全局模式下,正则的匹配结果为,true和false依次交替。这是因为: 在全局匹配模式下可以对指定要查找的字符串执行多次匹配。每次匹配使用当前正则对象的lastIndex属性的值作为在目标字符串中开 始查找的起始位置。lastIndex属性的初始值为0,找到匹配的项后lastIndex的值被重置为匹配内容的下一个字符在字符串中的位置索引,用来标识下次执行匹配时开始查找的位置。如果找不到匹配的项lastIndex的值会被设置为0。当没有设置正则对象的全局匹配标志时lastIndex属性的值始终为0,每次执行匹配仅查找字符串中第一个匹配的项。 lastIndex, 是一个可读可写的属性。需要特别注意是的,如前所述,正则表达当指定了g(全局匹配)或者y(粘性匹配),均会有这个效果。

全局匹配的一个使用场景——循环遍历,获取所有匹配。

var result = null;while ((result = globalre.exec(str)) != null){console.log(result[0]);console.log(globalre.lastIndex);}

当然使用matchAll()方法也可以实现该效果,这里不再赘述。


粘性匹配

sticky 属性反映了搜索是否具有粘性( 仅从正则表达式的 lastIndex 属性表示的索引处搜索 )。sticky是正则表达式对象的只读属性。sticky 的值是 Boolean ,并在“y”标志使用时为真; 否则为假。

var str = '#foo#';var regex = /foo/y;regex.lastIndex = 1;regex.test(str); // true (译注:此例仅当 lastIndex = 1 时匹配成功,这就是 sticky 的作用)regex.lastIndex = 5;regex.test(str); // false (lastIndex 被 sticky 标志考虑到,从而导致匹配失败)regex.lastIndex; // 0 (匹配失败后重置)

进阶知识

接下来我会讲一下,正则里面比较进阶且我觉得比较重要的内容。如前所述,这部分内容,我强烈推荐阅读这篇文章正则表达式30分钟入门教程。为了不做重复工作,这里我会讲得比较简略。

分支

所谓分支,是指有几种规则,如果满足其中任意一种规则都应该当成匹配,具体方法是用|把不同的规则分隔开。0d{2}-d{8}|0d{3}-d{7}

分组

所谓分组,类似于编码中的表达式的功能。用小括号来指定子表达式(也叫做分组),然后你就可以指定这个子表达式的重复次数了。如下所示(d{1,3}.){3}d{1,3}

贪婪与懒惰

当正则表达式中包含能接受重复的限定符时,通常的行为是(在使整个表达式能得到匹配的前提下)匹配尽可能多的字符。以这个表达式为例:a.*b,它将会匹配最长的以a开始,以b结束的字符串。如果用它来搜索aabab的话,它会匹配整个字符串aabab。这被称为贪婪匹配。

有时,我们更需要懒惰匹配,也就是匹配尽可能少的字符。前面给出的限定符都可以被转化为懒惰匹配模式,只要在它后面加上一个问号?即可。懒惰限定符如下

a.*?b匹配最短的,以a开始,以b结束的字符串。如果把它应用于aabab的话,它会匹配aab(第一到第三个字符)和ab(第四到第五个字符)。

断言

接下来的四个用于查找在某些内容(但并不包括这些内容)之前或之后的东西, 也就是说它们像b,^,$那样用于指定一个位置,这个位置应该满足一定的条件(即断言),因此它们也被称为零宽断言。

先行断言

x(?=exp),先行断言: exp紧跟x的情况下匹配x。例如,对于/Jack(?=Sprat)/,“Jack”在跟有“Sprat”的情况下才会得到匹配./Jack(?=Sprat)/ “Jack”后跟有“Sprat”或“Frost”的情况下才会得到匹配。不过, 匹配结果不包括“Sprat”或“Frost”

let regex = /First(?= test)/g;console.log('First test'.match(regex)); // [ 'First' ]console.log('First peach'.match(regex)); // nullconsole.log('This is a First test in a year.'.match(regex)); // [ 'First' ]console.log('This is a First peach in a month.'.match(regex)); // null

负向先行断言

x(?!exp),负向先行断言: x后无exp紧随的情况下匹配x。例如,对于/d+(?!。)/,数字后没有跟随小数点的情况下才会得到匹配。对于/d+(?!.)/.exec(3.141),匹配‘141’而不是‘3’。

console.log(/d+(?!.)/g.exec('3.141')); // [ '141', index: 2, input: '3.141' ]

后行断言

(?<=exp)x,后行断言: x紧随exp的情况下匹配x。例如,对于/(?<=Jack)Sprat/,“Sprat”紧随“Jack”时才会得到匹配。对于/(?<=Jack|Tom)Sprat,“Sprat”在紧随“Jack”或“Tom”的情况下才会得到匹配。不过,匹配结果中不包括“Jack”或“Tom”。

let oranges = ['ripe orange A ', 'green orange B', 'ripe orange C',];let ripe_oranges = oranges.filter( fruit => fruit.match(/(?<=ripe )orange/));console.log(ripe_oranges); // [ 'ripe orange A ', 'ripe orange C' ]

负向后行断言

(?

断言实战

提取字符串123sadf21(aaaaf213sdaf),括号中的部分。

如上图所示,(?<=().+(?=)), 该正则分为三部分:(?<=(,这是后行断言;(?=)), 这是先行断言;.+,匹配任意长的字符。

写在最后

以上就是本文的所有内容。正则使用得好,能起到事半功倍的作用。利用好本文推荐的工具,多加练习,相信正则一定不再是烦恼!

推荐JavaScript经典实例学习资料文章

《「速围」Node.js V14.3.0 发布支持顶级 Await 和 REPL 增强功能》

《深入细品浏览器原理「流程图」》

《JavaScript 已进入第三个时代,未来将何去何从?》

《前端上传前预览文件 image、text、json、video、audio「实践」》

《深入细品 EventLoop 和浏览器渲染、帧动画、空闲回调的关系》

《推荐13个有用的JavaScript数组技巧「值得收藏」》

《前端必备基础知识:window.location 详解》

《不要再依赖CommonJS了》

《犀牛书作者:最该忘记的JavaScript特性》

《36个工作中常用的JavaScript函数片段「值得收藏」》

《Node + H5 实现大文件分片上传、断点续传》

《一文了解文件上传全过程(1.8w字深度解析)「前端进阶必备」》

《【实践总结】关于小程序挣脱枷锁实现批量上传》

《手把手教你前端的各种文件上传攻略和大文件断点续传》

《字节跳动面试官:请你实现一个大文件上传和断点续传》

《谈谈前端关于文件上传下载那些事【实践】》

《手把手教你如何编写一个前端图片压缩、方向纠正、预览、上传插件》

《最全的 JavaScript 模块化方案和工具》

《「前端进阶」JS中的内存管理》

《JavaScript正则深入以及10个非常有意思的正则实战》

《前端面试者经常忽视的一道JavaScript 面试题》

《一行JS代码实现一个简单的模板字符串替换「实践」》

《JS代码是如何被压缩的「前端高级进阶」》

《前端开发规范:命名规范、html规范、css规范、js规范》

《【规范篇】前端团队代码规范最佳实践》

《100个原生JavaScript代码片段知识点详细汇总【实践】》

《关于前端174道 JavaScript知识点汇总(一)》

《关于前端174道 JavaScript知识点汇总(二)》

《关于前端174道 JavaScript知识点汇总(三)》

《几个非常有意思的javascript知识点总结【实践】》

《都2020年了,你还不会JavaScript 装饰器?》

《JavaScript实现图片合成下载》

《70个JavaScript知识点详细总结(上)【实践】》

《70个JavaScript知识点详细总结(下)【实践】》

《开源了一个 JavaScript 版敏感词过滤库》

《送你 43 道 JavaScript 面试题》

《3个很棒的小众JavaScript库,你值得拥有》

《手把手教你深入巩固JavaScript知识体系【思维导图】》

《推荐7个很棒的JavaScript产品步骤引导库》

《Echa哥教你彻底弄懂 JavaScript 执行机制》

《一个合格的中级前端工程师需要掌握的 28 个 JavaScript 技巧》

《深入解析高频项目中运用到的知识点汇总【JS篇】》

《JavaScript 工具函数大全【新】》

《从JavaScript中看设计模式(总结)》

《身份证号码的正则表达式及验证详解(JavaScript,Regex)》

《浏览器中实现JavaScript计时器的4种创新方式》

《Three.js 动效方案》

《手把手教你常用的59个JS类方法》

《127个常用的JS代码片段,每段代码花30秒就能看懂-【上】》

《深入浅出讲解 js 深拷贝 vs 浅拷贝》

《手把手教你JS开发H5游戏【消灭星星】》

《深入浅出讲解JS中this/apply/call/bind巧妙用法【实践】》

《手把手教你全方位解读JS中this真正含义【实践】》

《书到用时方恨少,一大波JS开发工具函数来了》

《干货满满!如何优雅简洁地实现时钟翻牌器(支持JS/Vue/React)》

《手把手教你JS 异步编程六种方案【实践】》

《让你减少加班的15条高效JS技巧知识点汇总【实践】》

《手把手教你JS开发H5游戏【黄金矿工】》

《手把手教你JS实现监控浏览器上下左右滚动》

《JS 经典实例知识点整理汇总【实践】》

《2.6万字JS干货分享,带你领略前端魅力【基础篇】》

《2.6万字JS干货分享,带你领略前端魅力【实践篇】》

《简单几步让你的 JS 写得更漂亮》

《恭喜你获得治疗JS this的详细药方》

《谈谈前端关于文件上传下载那些事【实践】》

《面试中教你绕过关于 JavaScript 作用域的 5 个坑》

《Jquery插件(常用的插件库)》

《【JS】如何防止重复发送ajax请求》

《JavaScript+Canvas实现自定义画板》

《Continuation 在 JS 中的应用「前端篇」》

作者:李一二

转发链接:https://mp.weixin.qq.com/s/PmzEbyFQ8FynIlXuUL0H-g

dreamweaver 正则表达式为属性值加上双引号_「前端篇」不再为正则烦恼相关推荐

  1. dreamweaver 正则表达式为属性值加上双引号_PHP正则表达式核心技术完全详解 第2节...

    PHP 正则表达式核心技术完全详解 第2节 接上一节内容 1 普通字符作为原子 /5/ 用于匹配字符串中是否有5这个字符出现 /php/ 用于匹配字符串中是否有PHP字符串出现 /  / 匹配空字符串 ...

  2. dreamweaver 正则表达式为属性值加上双引号_Python正则表达式(一)

    Python正则表达式 正则表达式是处理字符串的强大工具,拥有独特的语法和独立的处理引擎. 我们在大文本中匹配字符串时,有些情况用str自带的函数(比如find, in)可能可以完成,有些情况会稍稍复 ...

  3. dreamweaver 正则表达式为属性值加上双引号_IT兄弟连 HTML5教程 HTML5表单 新增的表单属性3...

    9 novalidate novalidate是属性规定在提交表单时不应该验证form和input域.novalidate属性适用于的类型有:text.search.url.telephone.ema ...

  4. Excel批量给字符加上双引号

    在实际开发中,会遇到这样的需求,大量的数据,需要从配置文件里读取,客户给到的枚举值是字符串,而配置文件里的数据,是json格式,需要加上双引号,这样就需要使用Excel来批量格式化一下数据. 1,鼠标 ...

  5. 搜狗输入法如何输入直角引号(「『』」 )

    直角引号(「『』」) 搜狗拼音输入法 菜单 --> 设置属性 --> 高级 --> 自定义标点符号 将引号的设置由圆引号改为直角引号. 如何修改: 将该网页中的直角符号复制,粘贴到相 ...

  6. python快速加引号_在python中如何快速地将一串字符串首尾加上双引号?

    python初学者.现在想做一个打包的小任务.目标地址为: D:\py_backup_test\iu d 然后将这个地址放在target_dir 里,并加上当前时间和后缀名: import os im ...

  7. HTML中属性值是否加引号规则详解

    说明: 当属性值是一个单词或者一整串(中间不含空格)的字符时:可以不加引号 当属性值是多个单词或者一整串(中间含空格)的字符时:需要加引号 备注:以上是老师的原话,个人实验发现,具体加不加引号是以是值 ...

  8. python类的属性前加上双下划线_在Python中使用双下划线防止类属性被覆盖

    在使用Python编写面向对象的代码时,咱们会经常使用"继承"这种开发方式.例以下面这一段代码:python class Info: def __init__(self): pas ...

  9. java正则表达式双引号_正则表达式中的双引号

    跟进我之前的问题here . 我意识到我需要对我的正则表达式案例更加具体,以获得适合我案例的答案 . 我已经用这个正则表达式打了很长时间(也使用我之前的问题的答案),我似乎无法构建我需要的东西 . 我 ...

最新文章

  1. ubuntu设置不同的eigen版本
  2. Django博客系统(首页用户名展示)
  3. JS的Object.keys
  4. mailbox 编程_MailboxProcessor从C#
  5. Python精通-运算符与基本数据类型(三)
  6. mysql命令行的几个用法
  7. 微信小程序性别代码对应描述
  8. SQL系列(五)—— 排序(order by)
  9. NG-ZORRO 7.0.0 发布,Ant Design 的 Angular 实现
  10. 史上最新最全的Android培训机构大揭秘
  11. 高精度三维扫描仪用于运动鞋逆向建模
  12. 芯片数据分析步骤5 过滤探针
  13. 给wordpess博客的数据库减肥提速
  14. python_PEP 8: E703 statement ends with a semicolon
  15. 载入pytorch的预训练模型时遇到_pickle.UnpicklingError: unpickling stack underflow
  16. 一个菜鸟的Geant4入门之路:alpha粒子轰击金箔的例子
  17. 【翻译】 XDP的力量
  18. post请求将formdata 转json
  19. SSM整合Ueditor的上传图片功能常见错误解决办法
  20. tomcat支持中文

热门文章

  1. 读数据库所有表和表结构的sql语句了(mssql)
  2. PHP页面跳转几种实现方法
  3. 华为机试HJ50:四则运算
  4. 数格子算面积的方法_面试小学数学经典教案:《什么是面积》
  5. pm2.5测试软件,测pm2.5的软件准吗
  6. java实现功能6_Java 6
  7. c3p0 服务启动获取连接超时_c3p0获取连接Connection后的Close()---释疑
  8. python21天打卡day7-字典
  9. 测试心得:细说从逻辑到数据的用例设计
  10. 从外行到外包,从手工测试到知名互联大厂测开 我经历了我这个年龄段不该经历的事情...