开题

我们常常有正则的各种需求,普通的正则匹配符虽然够用,但是满足不了我们一些很奇怪的需求,所以我们需要更多的关于正则的知识点。

需求

比如我们有一个这样的需求,匹配出字符串里的第一个div标签:aa<div>test1</div>bb<div>test2</div>cc

有这样一个表达式,它的匹配结果是:

`aa<div>test1</div>bb<div>test2</div>cc `.match(/<div>.*<\/div>/)  //<div>test1</div>bb<div>test2</div>

还有这样一个表达式,它的匹配:

`aa<div>test1</div>bb<div>test2</div>cc `.match(/<div>.*?<\/div>/)  //<div>test1</div>

区别只是第二个匹配多加了个?号。竟有如此操作。

正则贪婪匹配和非贪婪匹配

概念

贪婪与非贪婪模式影响的是被量词修饰的子表达式的匹配行为,贪婪模式在整个表达式匹配成功的前提下,尽可能多的匹配,而非贪婪模式在整个表达式匹配成功的前提下,尽可能少的匹配。非贪婪模式只被部分NFA引擎所支持。

例如

除了第一个例子,我们再举个例子。最简单的比如

`aaaaaa`.match(/\w+/)  //aaaaaa
`aaaaaa`.match(/\w+?/) //a

非贪婪模式的语法

js的正则引擎包括现在大部分的高级语言的正则引擎都是NFA,默认贪婪匹配的,js的匹配符都是贪婪匹配的匹配符也叫匹配优先量词,比如“{m,n}”、“{m,}”、“?”、“*”和“+”。

非贪婪模式的匹配符也叫忽略优先量词,比如“{m,n}?”、“{m,}?”、“??”、“*?”和“+?”。 就是在贪婪量词后面加?号

非贪婪模式的应用

并没有特殊的应用范围,因为正则是需要各种匹配符配合的。

贪婪模式和贪婪模式的性能

非贪婪模式的性能要高一点的,是因为贪婪模式可能会遇到更多的回溯。

NFA的回溯

谈到回溯,其实就是正则的匹配原理了。例子说话:

`love`.match(/l(ovv|asd|ove)/)  //love

那么js是如何对这段正则进行匹配的呢

  • 首先控制权交给l,匹配l,成功。
  • 匹配第一个分支,ovv,o匹配成功,继续匹配v匹配成功,e匹配失败,这时回溯,返回第一次成功的匹配l,并且废弃掉此分支。
  • 匹配第二个分支,a,匹配失败,回溯,废弃掉此分支。
  • 匹配第三分支ove,连续匹配都能成功,返回love。

回溯的原理:

记录所有可能的表达式分支,尝试匹配,若失败则返回,选择上次正确标记处按新的表达式(备用状态)开始新的尝试匹配。

回溯就是当正则匹配失败退回成功的匹配。因为js默认是贪婪匹配的,所以如果我们匹配这样一个字符串aaaaaaaaab,表达式为/a+c/。流程是怎样的呢?

因为贪婪,我们会先匹配全部的a,然后匹配c字符串,匹配失败,这是回溯,吐出一个a来,再匹配c,仍然失败,会再吐出一个a再匹配c,如此往复的回溯,直到剩下最后一个a,再匹配c失败,我们宣布匹配失败。这时已经做了n多次的回溯。所以刚才说贪婪匹配的性能可能是更低的,但也不是绝对的,要取决于你的正则是如何书写的。好的正则需要更少的回溯,会有更好的性能。

正则的捕获和非捕获

捕获和非捕获和下面要讲的环视都是NFA引擎区别与DFA引擎的重要部分。捕获的表达式很简单,就是(exp),非捕获的表达式是(?:exp)。捕获的作用就是会捕获括号里的内容,把它放到RegExp.$1 -$9 之中,非捕获的话就是我匹配这个表达式,但是我不把它放到返回中。

比如:

`email:xiaoming@toutiao.com`.match(/:(\w+)@/)  //[":xiaoming@", "xiaoming", index: 5, input: "email:xiaoming@toutiao.com"]

match函数的第一个返回是全文的匹配,第二个返回是RegExp.$n,即捕获的匹配,我们这样写就很容易获取到xiaoming这个用户名,如果我们写为

`email:xiaoming@toutiao.com`.match(/:(?:\w+)@/)  //[":xiaoming@", index: 5, input: "email:xiaoming@toutiao.com"]

是非捕获但匹配,就是相当于/:\w+@/。它有什么用呢?可以把一个东西作为一个整体,比如你可以写/\w{2}/你不能写/\w{2}+/,你可以写做/(?:\w{2})+/。

正则表达式的环视

最后说一下正则最难的环视。也有文章叫预搜索。

  • 环视只进行子表达式的匹配,不占有字符,匹配到的内容不保存到最终的匹配结果,是零宽度的。环视匹配的最终结果就是一个位置。
  • 环视的作用相当于对所在位置加了一个附加条件,只有满足这个条件,环视子表达式才能匹配成功。
  • js只支持顺序环视,包括顺序肯定环视和顺序否定环视。

顺序肯定环视

表达式为:(?= exp)。表达式的右侧需要满足exp,才能成功匹配。比如

var con="coming soon,going gogogo"
var reg = /\b[\w]+(?=ing\b)/g; //["com", "go"]
console.log(con.match(reg));

\w+需要满足的条件是(ing\b),顺序肯定环视的表达式满足,才可以匹配。意思就是相当于匹配后面带ing的单词。

`a12`.match(/^(?=[a-z])[a-z0-9]+$/)    //a12

这个匹配是如何进行的呢?

首先^匹配位置0,a字母匹配成功,然后进入顺序肯定环视,它和表达式的匹配是不互斥的,它也匹配的a,a匹配成功,进入表达式,匹配a,匹配1,2都成功,$匹配成功,返回a12。

^匹配"",[a-z0-9]匹配”a12“,$匹配“”。

/(?=.*?\d)/.test(`asdasdads`)  //匹配字符必须有数字

`<a class='a'>>>asdasdw我啊啊售出<<<<</a>`.match(/(?:<a.*?>)(.*?)(?=<\/a>)/)
// ["<a class='a'>>>asdasdw我啊啊售出<<<<", ">>asdasdw我啊啊售出<<<<", index: 0, input: "<a class='a'>>>asdasdw我啊啊售出<<<<</a>"]

顺序否定环视

表达式为:(?!exp)。相当于在当前位置左侧附加一个条件。如果满足了exp则顺序否定环视宣布匹配失败,如果不满足exp,顺序否定环视宣布匹配成功,再进行下面的匹配。

比如

`1111a112`.match(/^(?![\d]+$)/g) //匹配字符不能全是数字

最后一道题

给金钱数额加千分制的区分,比如1,234,567,890。

`1234567890`.match(/\d{1,3}(?=(\d{3})+$)/g)

\d首先贪婪匹配123,成功,进入顺序肯定环视,456,789匹配成功,控制权交到$匹配789,匹配失败,回溯

\d匹配12,成功,进入顺序肯定环视,345,678匹配成功,控制权交到$匹配678,匹配失败,回溯

\d匹配1,成功,进入顺序肯定环视,234,567,890,控制权交到$匹配890,匹配成功.

\d贪婪匹配234,成功,进入顺序肯定环视,567,890匹配成功,控制权交到$匹配890,匹配成功

\d贪婪匹配567,成功,进入顺序肯定环视,890匹配成功,控制权交到$匹配890,匹配成功

\d贪婪匹配890,成功,进入顺序肯定环视,匹配空字符串匹配失败,匹配失败。

\d匹配89,\d匹配8在顺序肯定环视里都会失败,于是返回。

文档匹配1,234,567

深入js正则的更多相关文章

  1. js正则

    JS正则 test:判断字符串是否符合规定的正则 rep = /\d+/; rep.test("asdfoiklfasdf89asdfasdf") # true rep = /^\ ...

  2. js正则匹配的一个日常应用

    应用实例 1 /** 将段落中的 \n 转换为 <p></p>, 规范存储 */ 2 function formatParagraphForStore(val) { 3 var ...

  3. jS正则和WEB框架Django的入门

    JS正则 -test 判断字符串是否符合规定的正则表达式 -exec 获取匹配的数据 test的例子: 从上述的例子我们可以看出,如果rep.test匹配到了就返回true,否则返回false exe ...

  4. js正则实现二代身份证号码验证详解

    js正则实现二代身份证号码验证详解 根据[中华人民共和国国家标准 GB 11643-1999]中有关公民身份号码的规定,公民身份号码是特征组合码,由十七位数字本体码和一位数字校验码组成.排列顺序从左至 ...

  5. js 正则 以字母开头必须有 大小写字母数字组成 可以有“@"或 ”.“

    js  正则  以字母开头必须有 大小写字母数字组成 可以有“@"或 ”.“ var reg = /^[a-zA-Z]{1}(?=.*[a-z])(?=.*[A-Z])[a-zA-Z\d_@ ...

  6. 手机号码js正则验证

    手机号码js正则验证 var myreg = /^(((13[0-9]{1})|(15[0-9]{1})|(18[0-9]{1}))+\d{8})$/; if (!myreg.test($(" ...

  7. js正则标志/g /i /m的用法,以及实例

    js正则标志/g /i /m的用法,以及实例   正则的思想都是一样的,但是具体的写法会有所不同,在这里提到的/g,/i,/m在其他的地方也许就不能用了. 一,js正则标志/g,/i,/m说明 1,/ ...

  8. 记录一下JS正则的坑

    JS正则的单行模式有点问题 总之 . 符号匹配换行符号会有问题 暂时的解决方案是 html = html.replace(/[\r\n]/g,""); 附加一个 html = ht ...

  9. 奇怪的JS正则之 /[A-z]/.test("\\"); // true

    本文是在一个国外介绍JS的网站上转载过来的,作者很逗,先是举例JS让人XX的例子,再动手实践发现JS隐藏的黑知识.为什么 /[A-z]/.test("\\"); 是 true ,你 ...

  10. 撸一个JS正则小工具

    写完正则在浏览器上检测自己写得对不对实在是不方便,于是就撸了一个JS正则小demo出来. demo demo展示 项目地址 代码部分 首先把布局样式先写好. <!DOCTYPE html> ...

随机推荐

  1. 读《你不知道的JavaScript(上卷)》后感-浅谈JavaScript作用域(一)

    原文 一. 序言 最近我在读一本书:<你不知道的JavaScript>,这书分为上中卷,内容非常丰富,认真细读,能学到非常多JavaScript的知识点,希望广大的前端同胞们,也入手看看这 ...

  2. 流API--原始类型流

    到目前为止,我们已经将整型收集到了一个Stream<Integer>的流中,不过将每个整数包装成相应对象显然是一个低效的做法,对于其他的基本类型也是一样,我们前面说过jdk提供包装类已经自 ...

  3. 关于 tomcat 配置时遇到的问题与警告及解决办法

    首先,我们在日常配置 tomcat 时,总是会遇到这样的问题: 有时候我们会重新头来配置 tomcat,但是现在我们并不需要那么做,方法很简单,请继续往下看: 这个问题是告诉我们 tomcat 在 4 ...

  4. svn: resource out of date; try updating的解决

    问题: svn提交文件时提示错误:resource out of date; try updating.说明该资源版本有问题,尝试更新svn,发现该文件没有可更新的内容.于是查看资源历史,发现有人第一 ...

  5. Activity的setContentView的流程

    最简单的Activity中的内容大致是这样的: public class MainActivity extends Activity { @Override public void onCreate( ...

  6. ATS缓存数据结构

    ATS缓存数据结构 HttpTunnel类 数据传输驱动器(data transfer driver),包含一个生产者(producer)集合,每个生产者连接到一个或是多个消费者(comsumer). ...

  7. oracle case when及decode的用法

    case ... when 语句 1) CASE column_name WHEN value1 THEN resutl1,... [ ELSE result ] END select name , ...

  8. Web安全之CSP

    内容安全策略(Content-Security-Policy,简称CSP) 概念: 内容安全策略(CSP)是一种web应用技术用于帮助缓解大部分类型的内容注入攻击,包括XSS攻击和数据注入等,这些攻击 ...

  9. Centos系统下硬盘扩容

    装好CentOS后,发现空间太小,怎样才能增加硬盘容量?那就是再建一个硬盘: 打开虚拟经济的设置添加硬盘 查看现有的磁盘空间 fdisk -l [root@localhost ~]# fdisk -l ...

  10. spring之AspectJ基于注解 AOP编程

    一.前言 使用注解代替之前在spring配置文件中配置目标类.切面类和aop配置. 二.注意 需要注意的是,需要在spring配置文件中引入如下,如果不添加,切面类中的@Aspect注解将不起作用 & ...