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!
  • 相关阅读:
    导入已有项目到svn
    Linux用ICMP协议实现简单Ping网络监测功能
    c++ tcp 服务器和客户端例子
    C++ Socket 编程
    c++工厂模式和多线程结合
    Linux中ls命令详解
    Mac OS X 11中的/usr/bin 的“Operation not permitted”
    Warning: mysql_connect(): No such file or directory 解决方案总结(操作系统: Mac)
    页面组件渲染小组件(重点)
    Vue 路由
  • 原文地址:https://www.cnblogs.com/Shadowplay/p/9672303.html
Copyright © 2011-2022 走看看