资讯专栏INFORMATION COLUMN

[前端工坊]正则表达式-从模糊到清晰

FullStackDeveloper / 552人阅读

摘要:作者京东商城成都研究院研发部卢兴元正则表达式从模糊到清晰什么是正则简单点,正则是一些用来匹配和处理文本的字符串或者叫工具,往往用于查找特定的信息搜索,或者查找并编辑特定的信息替换。

文章来自微信公众号:前端工坊(fe_workshop),不定期更新有趣、好玩的前端相关原创技术文章。 如果喜欢,请关注公众号:前端工坊
版权归公众号所有,转载请注明出处。
作者:京东商城-成都研究院-JSHOP研发部 卢兴元

正则表达式-从模糊到清晰 1. 什么是正则

简单点,正则是一些用来匹配和处理文本的字符串(或者叫工具),往往用于查找特定的信息(搜索),或者查找并编辑特定的信息(替换)。它是一种内置在其他语言里的一种“迷你”语言,比如内置在Javscript、Java等语言中。

2. 要认可的事实

正则答案不唯一。几乎所有的问题,往往都会有不止一种解决方案。有的比较简单,有的比较快速,有点兼容性更好,有的功能更全。我们需要依据自己的需求,确认一种最适合自己的方案。

3. 正则引擎概述

正则引擎可以分为2类。一种称之为NFA(非确定型有穷自动机),另一种称之为DFA(确定型又穷自动机)。嗯,概念不好理解,我们举个栗子:
正则:to(Jack|Rose|Jerry)
匹配文本:xxx···toJerry

1)NFA(表达式主导)匹配过程

正则表达式从正则的第一个 t 开始,每次由正则引擎查看表达式的一部分,同时检查当前文本是否匹配表达式的当前部分。如果是,则继续表达式的下一部分,如果继续,直到表达式的所有部分都能匹配到。此时发现当检查到当前文本中的字符 t 时,所以正则表达式的第一项匹配成功,接着会检查紧跟其后的字符是否能由 o 来匹配,然后发现可以,则接着检查后面的元素,此时后面的元素是 (Jack|Rose|Jerry) ,引擎会尝试着3种可能进行分别测试,直到匹配成功。

2)DFA(文本主导)匹配过程

引擎在扫码当前文本的时候,会记录当前有效的所有匹配可能。当引擎移动到文本的 t 时,它会在当前处理的匹配可能中添加一个潜在的可能:

接下来扫描的每个字符,都会更新当前的可能匹配序列。例如扫码到匹配文本的 J 时,有效的可能匹配变成了2个,Rose被淘汰出局。

扫描到匹配文本的 e 时,Jack也被淘汰出局,此时就只剩一个可能的匹配了。当完成后续的rry的匹配时,整个匹配完成。

3)两句话点评NFA与DFA

1、DFA匹配速度快但特性少(比如不支持捕获组、反向引用),NFA匹配稍慢但能力强大;
2、DFA就好比搭载电动发动机的汽车,加速度很快,但续航短,不能出远门,而NFA可以认为是汽油发动机的汽车,加速度没那么快,但是适应性广,哪里都能去,但由于适应性广,所以调教很重要。

4)需要注意的

Java、Javascript、PHP、Python这些都是NFA引擎。

4. 过基础(老手请跳过)

5. 要点讲解 1)贪婪与懒惰
贪婪模式:

尽可能匹配更多的字符。举个栗子:
正则:

.*

结果:

从匹配过程我们也可以发现对于 .* 这个表达式会尝试尽可能多的匹配字符,直到匹配到尽头,才尝试匹配正则结尾的

懒惰模式:

与贪婪模式相反,尽可能匹配更少的字符。举个栗子:
正则:

.*?

结果:

从匹配过程我们也可以发现,会优先匹配正则结尾的

,在没有满足此结尾的情况下,才尽可能的去少匹配 .*? 这个表达式。

2)子表达式与反向引用
子表达式:

考虑这种场景,有些短语虽然由多个单词构成,但其实是一个整体,需要把它当做一个独立元素来使用,这种时候就需要使用子表达式。子表达式必须用()圆括号括起来。用途就是,可以精确的设定需要重复匹配的文本及重复次数。

反向引用:

它允许我们在正则中引用之前子表达式匹配到的结果。这有什么用?还是举个栗子:

需求:匹配Html代码片段中的h1~h6标签
正则:.*?(没有使用反向引用)

结果:

正则:.*?(使用了反向引用)

结果:

3)回溯

NFA引擎匹配能力强大,但是调教不好,有可能引发性能问题,它有另一个叫法,叫做回溯失控。那么问题来了,什么是回溯?

举个栗子:
我们醒来的时候,突然发现被困在山洞里,这时候需要寻找出路,然而前方是一个岔路口。这个时候也并没有任何依据可以告诉我们哪一条是出路,只有挨个尝试,于是我们可以在岔路口做个标记,以便万一选择的这条路走不通,可以原路返回,直到遇见做了标记的岔路口,以便继续尝试另一条路是不是出路。我们可以把每次尝试失败然后往回走,找到之前做标记的地方的这个过程,称之为回溯。
很多情况下,依据你写的正则表达式,正则引擎或多或少都需要进行这种2个或者多个选项的选择。

4)断言(环视)

先不做专业术语解释,先来看这么一个应用场景
需求:匹配网页里所有PC商品详情页地址所包含的sku信息
PC商品详情页地址格式://item.jd.com/xxxxxx.html

方法一:先正则匹配,再截断后面固定的.html

正则:/d+.html/g

方法二:先正则匹配,再截断前后固定的字符

正则:/item.jd.com/d+.html/g

方法三:使用正向断言和反向断言,保证准确性,同时只返回sku数字

正则:/(?<=item.jd.com/)d+(?=.html)/g

断言分类:正向肯定断言、正向否定断言、反向肯定断言、反向否定断言

需要注意的:Javascript不支持反向断言,Java也是有限制的支持反向断言
总而言之,言而总之,当我们匹配目标关键字的时候,同时期望对目标关键字的前后进行限制,并且又不期望这些限制会出现在匹配结果中。这时候,就可以使用断言。

6. 正则优化 1)怎样才算是一个好正则
准确性:只匹配期望的文本,排除掉不期望的文本

需求:匹配jshop手机活动页url的域名部分
jshop手机活动页URL格式://xxxx.jd.xxx/m/act/xxxxxx.html
正则:///(.*)(?=/m)/g

正则:///(1*)/g

点评:如果不需要匹配/,那就应该在正则表达式中作出这样的规定

匹配效率:很快返回匹配结果,如果不能匹配,尽可能短的时间报告匹配失败

前面有提到过,NFA引擎功能强大,但是写不好很容易引发效率问题。其中太多的多选分支很容易成为效率杀手,因为任何多选分支只要匹配失败,都会导致回溯。所以提高正则匹配效率的方法之一就是减少多选分支。

举个栗子:

需求:匹配用户输入的一个字符串是否是一个4位IP里的一位,直白的说就是匹配0~255
分析:可能有1位,也可能有2位,也可能有3位。3位的时候需要分开判断,当第一位是0或者1的时候,后面两位可以是任意数字。当第一位是2的时候,第二位只能是0-5。并且当第二位是0-4的时候,第三位可以是任意数字,但第二位是5的时候,第三位只能是0-5。
翻译过来正则:/d|dd|[01]dd|2[0-4]d|25[0-5]/
合并同类项后:/[01]?dd?|2[0-4]d|25[0-5]/

点评:可以通过合并同类项来减少多选分支。同时第一个多选分支使用的是 dd? 而不是 d?d ,这样如果根本不存在数字,NFA引擎会更快地报告失败

易读性

……

2)使用工具
分析正则表达式

比如这个网站 https://jex.im/regulex
可以实现对复杂整个表达式的一个

测试正则表达式性能

比如这个猫头鹰工具 RegexBuddy
可以用来测试正则表达式的匹配过程以及性能,包括各种语言下的正则特性支持情况。

3)优化手段
优化方针:减少回溯

1、减少或者合并多选分支
2、避免量词的嵌套
3、占有优先量词。可以减少回溯,遗憾的是js不支持,但java支持。
举个栗子:考虑到 /a+b/ 和 /a++b/ 两个正则,测试的字符串 aaaa

/a+b/ 的匹配过程

/a++b/ 的匹配过程

4、使用正确的边界匹配器(^、$、b、B等),限定搜索字符串位置
5、尽量不使用通配符".";字符使用具体的元字符、字符类(d、w、s等)(推荐)
6、使用正确的量词(+、*、?、{n,m}),如果能够限定长度,匹配最佳
7、使用非捕获型括号。如果不需要引用括号内的文本,请使用非捕获型括号(?:……),好处就是节省捕获时间,同时减少回溯使用的状态数量。


  • / ↩

  • 文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

    转载请注明本文地址:https://www.ucloud.cn/yun/54463.html

    相关文章

    • [前端工坊]正则达式-模糊清晰

      摘要:作者京东商城成都研究院研发部卢兴元正则表达式从模糊到清晰什么是正则简单点,正则是一些用来匹配和处理文本的字符串或者叫工具,往往用于查找特定的信息搜索,或者查找并编辑特定的信息替换。 文章来自微信公众号:前端工坊(fe_workshop),不定期更新有趣、好玩的前端相关原创技术文章。 如果喜欢,请关注公众号:前端工坊版权归公众号所有,转载请注明出处。作者:京东商城-成都研究院-JSHO...

      piglei 评论0 收藏0
    • [前端工坊]正则达式-模糊清晰

      摘要:作者京东商城成都研究院研发部卢兴元正则表达式从模糊到清晰什么是正则简单点,正则是一些用来匹配和处理文本的字符串或者叫工具,往往用于查找特定的信息搜索,或者查找并编辑特定的信息替换。 文章来自微信公众号:前端工坊(fe_workshop),不定期更新有趣、好玩的前端相关原创技术文章。 如果喜欢,请关注公众号:前端工坊版权归公众号所有,转载请注明出处。作者:京东商城-成都研究院-JSHO...

      wums 评论0 收藏0
    • [前端工坊]浅谈Web编程中的异步调用的发展演变

      摘要:三即生成器,它是生成器函数返回的一个对象,是中提供的一种异步编程解决方案而生成器函数有两个特征,一是函数名前带星号,二是内部执行语句前有关键字调用一个生成器函数并不会马上执行它里面的语句,而是返回一个这个生成器的迭代器对象。 文章来自微信公众号:前端工坊(fe_workshop),不定期更新有趣、好玩的前端相关原创技术文章。 如果喜欢,请关注公众号:前端工坊版权归微信公众号所有,转载请...

      qpwoeiru96 评论0 收藏0

    发表评论

    0条评论

    FullStackDeveloper

    |高级讲师

    TA的文章

    阅读更多
    最新活动
    阅读需要支付1元查看
    <