正则表达式 词法分析,正则表达式基本语法

  正则表达式 词法分析,正则表达式基本语法

  正则表达式是字符串操作的逻辑公式,是处理文本数据的重要而复杂的技术。那么如何快速掌握正则表达式呢?下面这篇文章推荐一种学习方法:通过AST。希望对大家有帮助!

  字符串处理基本都用正则表达式,字符串的匹配、提取、替换都非常方便。

  但是学习正则表达式还是比较困难的,比如贪婪匹配、非贪婪匹配、捕获子群、非捕获子群等。这些不仅初学者难以理解,很多工作了几年的人也难以理解。

  如何学习正则表达式?如何快速掌握正则表达式?

  推荐一个学习规则的好方法:通过 AST 来学习

  正则表达式的匹配原理是把模式串 parse 成 AST,然后通过这个 AST 去匹配目标字符串。

  模式中的各种信息将在解析后保存在AST中。AST是抽象语法树,意思是抽象语法树。顾名思义,它是按照语法结构组织起来的树。所以你可以从AST的结构中很容易的知道正则表达式支持的语法。

  如何检查正则表达式的AST?

  可以通过astexplorer.net网站直观查看:

  通过将parse的语言切换到RegExp,可以可视化正则表达式的AST。

  如前所述,AST 是按照语法来组织的一棵树,那么从它的结构上自然能容易地理清各种语法。

  所以我们从AST的角度来学习各种语法:

  

/abc/

  先说简单的,/abc/这样的正则性可以匹配 abc 的字符串,它的AST是这样的:

  3 Char,值分别为A,B,C,类型简单。之后的匹配就是遍历AST,分别匹配这三个字符。

  我们用exec的api进行了测试:

  第0个元素是匹配字符串,index是匹配字符串的起始下标。Input是输入字符串。

  让我们再次尝试特殊字符:

  

/\d\d\d/

  /\d \ d/表示匹配三个数字,\ d是规则支持的具有特殊含义的元字符。

  通过AST,我们还可以看到,虽然它们是Char,但类型是meta:

  您可以通过元字符\d匹配任何数字:

  哪些是元字符,哪些是简单字符,通过AST可以一目了然。

  

/[abc]/

  正则性支持通过[]的方式指定一组字符,也就是说可以匹配任意一个字符。

  通过AST,我们还可以看到它被包裹了一层CharacterClass,意思是字符类,也就是可以匹配它包含的任何字符。

  测试确实是这样的:

  

/a{1,3}/

  正则表达式支持以{from,to}的形式指定字符重复的次数,

  例如,/b{1,3}/表示字符B重复1到3次,而/[abc]{1,3}/表示这个a/b/c字符类重复1到3次。

  从AST中可以看出,这种语法称为重复:

  他有一个量词属性来表示量词,其中类型是范围,从1到3。

  正则性也支持一些量词的缩写,比如1到无数次,*代表0到无数次,0或1次。

  它们是不同类型的量词:

  可能有同学会问,这里的贪婪属性是什么意思?

  Greedy表示贪婪,这个属性表示这个重复是贪婪的还是非贪婪的。

  如果在量词后面加一个?你会发现greedy变成false,也就是切换到非greedy匹配:

  贪与不贪是什么意思?

  让我们来看一个例子。

  默认重复的匹配是贪婪的,只要满足条件,总是会匹配的,所以acbac这里可以匹配。

  量词后面加一?它被切换到非贪婪,并且它将只匹配第一个:

  这就是贪婪匹配和非贪婪匹配。我们可以通过AST清楚的知道贪婪和非贪婪是针对重复语法来说的,默认是贪婪匹配,在量词后加个 ? 就可以切换到非贪婪。

  

(aaa)bbb(ccc)

  正则表达式支持将部分匹配的字符串放入子组,并通过()返回。

  浏览一下AST:

  相应的AST称为Group。

  您会发现它有一个捕获属性,默认情况下是这样的:

  这是什么意思?

  这是子组捕获的语法。

  如果不想捕获子群,可以写(?aaa)

  看,捕捉已经变成假的了。

  捕捉和不捕捉有什么区别?

  让我们试试:

  哦,原来Group的捕捉属性是指是否提取。

  我们可以通过AST,捕获是针对子组来说的,默认是捕获,也就是提取子组的内容,可以通过 ?: 切换到非捕获,就不会提取子组的内容了。看到

  我们已经熟悉了使用AST来理解常规语法,所以让我们看看最难的部分:

  

/bbb(?=ccc)/

  正则表达式受(?=xxx)表达先行断言的语法,用于判断一个字符串前面是否有一个字符串。

  通过AST,你可以看到这个语法叫做断言,类型是lookahead,也就是向前看,它只匹配前面的意思:

  这是什么意思?为什么要写这个?和/bbb(ccc)/和/bbb(?ccc)/有什么区别?

  让我们试试:

  从结果可以看出:

  /bbb(ccc)/匹配ccc的子组并提取该子组,因为捕获了默认子组。

  /bbb(?ccc)/匹配了ccc的子群却因为我们通过了而没有提取?将子组设置为不采集。

  /bbb(?=ccc)/匹配ccc的子组未被提取,表示它也未被捕获。它和?的区别在于:匹配结果中不出现ccc。

  这就是前瞻断言的本质:先行断言代表某段字符串前面是某段字符串,对应的子组是非捕获的,而且断言的字符串不会出现在匹配结果中。

  如果后面没有那个字符串,就不匹配:

  :

/bbb(?!ccc)/

  ?=改成了?之后,意思就变了。浏览一下AST:

  尽管先行断言首先被断言,但是还有一个附加的属性,其负值为真。

  这个意思很明显。原来是前面有某串,否定之后就没有前面有某串了。

  那么匹配结果正好相反:

  现在,如果前面不是某个字符串,就会匹配。这是否定先行断言。

  

/(?=aaa)bbb/

  有一个前导断言,自然也有一个尾随断言,即跟随某个字符串进行匹配。

  同样,也可以否认:

  (?=aaa)对应的AST很容易想到,就是lookbehind断言:

  (?Aaa)对应的AST是添加一个否定属性:

  前断言和后断言是最难理解的正则表达式语法。AST是不是更好理解~

  

总结

  正则表达式是一个非常方便的处理字符串的工具,但是它的学习还是有些难度的。许多人对贪婪匹配、非贪婪匹配、捕获子组、非捕获子组、第一个断言和最后一个断言等语法感到困惑。

  我推荐通过AST学习规律性,AST是按照语法结构组织的对象树。通过AST节点的名称和属性可以很容易地整理出各种语法。

  例如,我们通过AST明确表示:

  重复语法(Repetition)就是字符 + 量词的形式,默认是贪婪匹配(greedy 为 true),代表一直匹配到不匹配为止,量词后加个 ? 就切换成了非贪婪匹配,匹配到一个字符就停止。

  子组语法(Group)是用于提取某段字符串的,默认是捕获(capturing 为 true),代表需要提取,可以通过 (?:xxx)切换到非捕获,只匹配不提取。

  断言语法(Assertion)代表前面或后面有某段字符串,分为先行断言(lookahead assertion)和后行断言(lookbehind assertion),语法分别是(?=xxx)和 (?=xxx),可以通过把 = 换成 ! 来表示否定(negative 为 true),意思正好反过来。

  是各种文档对语法理解深刻还是编译人员对语法理解深刻?

  不用问,肯定是编译器!

  那么通过它根据语法解析的语法树来学习语法,自然比通过文档来学习语法要好。

  正则表达式如此,其他语法的学习也是如此。如果你能用AST学习语法,你就不需要阅读文档。

  更多关于node的信息,请访问:nodejs教程!就是这样快速掌握正则表达式的。通过AST学习常规语法!更多详情请关注我们的其他相关文章!

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: