zoukankan      html  css  js  c++  java
  • 正则表达式学习笔记(二)表达式的匹配原理

    表达式的匹配原理

    一)正则引擎的分类

    1.DFA(符合或者不符合POSIX标准的都属于此类):电动机

    2.传统NFA: 传统的汽油机

    3.POSIX NFA:符合新标准的汽油机

    二)两条规则

    规则1:优先选择最左端的匹配结果

    匹配先从需要查找的字符串的起始位置尝试匹配,即从第一个字符开始测试整个正则表达式,如果测试了所有

    可能后仍然找不到结果,则从第二个字符开始测试,直到找到结果。

    例如:

    1.用'ORA'来匹配FLOARAL,从字符串左边开始的第一轮匹配会失败(因为ORA不能匹配FLO),同理

    第二轮也会失败,第三轮成功。

    2.用'cat'来匹配:

    The dragging belly indicates that your cat is too fat.

    匹配结果是indicates中的cat

    3.用'fat|cat|belly|your'匹配2中的句子,结果是?

    注意:锚点直接匹配位置。

    规则2: 标准量词是匹配优先的

    标准匹配量词:?,*,+,{min, max}

    如果用这些量词来约束某个表达式,例如'(tang)*'中的'tang', 'a?'中的'a',在匹配成功之前,进行尝试的次数是存在上限和下限的

    规则2表明这些尝试总是希望获得最长的匹配。它们总是尝试匹配尽可能多的字符串,直到匹配上限为止。

    例如:用'[0-9]+'匹配'TangJia19900326'能匹配字符串中的所有数字,这是因为1匹配成功之后,已经满足了匹配

    成功的下限了,但此时正则表达式是匹配优先的,所以它会继续匹配完所有的数字。

    过度的匹配优先:

    '^.*([0-9](0-9))'匹配过程:由于标准量词优先原则,'.*'会直接匹配完整行,此时'([0-9][0-9])在尝试匹配时会失败,这样它就会强迫'.*'交出

    一些字符供自己匹配,但这种‘强迫’是建立在不破坏'.*'匹配成功的条件之上的。

    例如,用上述表达式匹配'about a 25 girl chen','.*'匹配整个字符穿后,第一个'[0-9]'的匹配要求'.*'释放一个字符'n',但这并不能让'[0-9]'

    匹配,所以必须继续交还字符'e',直到释放'5'。但不幸的是第一个'[0-9]'虽然匹配成功了,第二个'[0-9]'仍然不能匹配。为了匹配整个

    正则表达式,此时必须释放'2'(给第一个匹配),第二个'[0-9]'开始匹配,并最后成功匹配到'5'。

    思考:用'^.*([0-9]+)'来匹配'tang 2003'   括号会捕获到什么?

    三)表达式主导和文本主导

     NFA引擎:表达式主导

    例如:用表达式'to(nite|knight|night)'匹配'...tonight...',表达式第一个元素是't',它将会重复尝试,

    直到在目标字符串中找到't',找到后再在目标字符串中查找'o',找到后会在目标元素中依次尝试'nite','knight',

    'night'三种可能匹配成功。尝试'nite'的过程和之前一样,一个字符一个字符地依次尝试。

    DFA引擎:文本主导

    回溯(Backtracking)

    基本原理----略。两个重要原则:

    1.对于匹配优先量词,会进行尝试,对于忽略优先量词,会跳过尝试

    2.后进先出

     忽略优先量词

    用'<B>.*?</B>'来匹配:

    <B>Billions</B> and <B>Zillions</B> of suns......

    开始匹配'<B>'之后,'.*?'首先决定不匹配任何字符,因为他是忽略优先的。

    于是控制权交给后面的'<'符号,此时遇到了字符串中的B无法匹配,控制权

    交还给'.*?',表达式便匹配到了B,因为是忽略优先的,控制权再次交给'<',

    在重复数次后,最终匹配到: ‘<B>Billions</B>’

    但如果我们用该表达式匹配: ‘<B>Billions<B> and <B>Zillions</B> of suns......’

    就会匹配到:‘<B>Billions<B> and <B>Zillions</B’,这不是我们想要的结果

    我们可以用否定环视解决这个问题:

     固化分组:(?>......)

    使用'(?>......)'的匹配与正常匹配的差别在于,如果匹配进行到结构结束后(也就是闭括号之后),结构体中的所有备用状态都将会被抛弃。

    例子: '(.dd(?>[1-9]?))d+'在固化分组内,量词能够正常工作,如果'[1-9]'不能匹配,正则表达式则会返回'?'留下的备用状态。

    然后脱离固化分组,继续前进到'd+'。在这种状态下,当控制权离开固化分组时,没有备用状态需要放弃。

     占有优先量词: ?+、 *+、 ++、 和{m,n}+

    占有优先量词和匹配优先量词的差别:不交还已经匹配的字符。

    环视中的回溯

    多选结构也是匹配优先的吗?

    1.对于大多数传统型NFA:按顺序匹配,前面的匹配成功就不尝试后面的。

    2.少数DFA和POSIX NFA:匹配优先,尽可能匹配更多的字符。

     四)NFA、DFA 和 POSIX

    最左最长规则

    NFA:按顺序来

    DFA:匹配最长的

    Simple is important!
  • 相关阅读:
    第二十一章流 1流的操作 简单
    第二十章友元类与嵌套类 1友元类 简单
    第十九章 19 利用私有继承来实现代码重用 简单
    第二十章友元类与嵌套类 2嵌套类 简单
    第十九章 8链表类Node 简单
    第二十一章流 3用cin输入 简单
    第十九章 10 图书 药品管理系统 简单
    第十九章 11图书 药品管理系统 简单
    第二十一章流 4文件的输入和输出 简单
    第十九章 12 什么时候使用私有继承,什么时候使用包含 简单
  • 原文地址:https://www.cnblogs.com/Shadowplay/p/9672303.html
Copyright © 2011-2022 走看看