正则引擎介绍

≡放荡痞女 提交于 2020-02-29 14:32:30

一.正则引擎的分类

1.正则引擎主要可以分为基本不同的两大类: DNF和NFA

同时可以粗略的分为三类: DFA(符合或不符合POSIX标准的都属此类)、传统型NFA、POSIX NFA.

2.部分程序使用的正则引擎类型

DFA: awk(多数版本)、egrep(多数版本)、flex、lex、Mysql、procmail

传统型NFA: GNU Emacs、Java、grep(多数版本)、less、more、.NET、PCRE library、Perl、PHP、Python、Ruby、sed(多数版本)、vi

POSIX NFA: nawk、Mortice Kern Systems'utilities、GNU Emacs(明确指定时使用)

DFN/NFA混合: GNU awk、GNU grep/egrep、Tcl

3.测试引擎的类型

<1>查看是否是传统型NFA 测试忽略优先量词是否得到支持,如果是基本就能确实是传统型的NFA.因为DFA是不支持忽略优先量词的,在POSIX NFA中也没有意义. <2>DFA还是POSIX NFA DFA也不支持捕获型括号和回溯.也不支持环视和固化分组和条件判断和忽略优先.这一点有助于判断. 关于POSIX NFA看三者的总结篇.

二.匹配的基础 1.总结两条普适的原则

优先选择最最左端(最靠开头)的匹配结果.
标准的匹配量词(* ? +和{m,n})是匹配优先的.

2.匹配过程-----"失败"

匹配先从需要查找的字符串的起始位置尝试匹配.在这里,"尝试匹配"的意思是:在当前位置测试整个正则表达式能匹配的每样文本,如果在当前位置测试了所有的可能之后不能找到匹配结果,就需要从字符串的第二个字符之前的位置开始重新尝试.在找到匹配结果以前必须在所有位置重复此过程.只有在尝试过所有的起始位置(直到字符串的最后一个字符)都不能找到匹配结果的情况下,才会报告"匹配失败".
所以,如果要用正则表达式"ORA"来匹配"FLORAL",从字符串左边开始第一轮尝试会失败(因为"ORA"不能匹配FLO),第二轮尝试也会失败("ORA"同样不能匹配"LOR"),从第三个字符开始的尝试能够成功,所以引擎会停下来,报告匹配结果FL"ORA"L.

三.传动装置和驱动过程

1.传动装置的主要功能:----驱动

如果引擎不能再字符串开始的位置找到匹配的结果,传动装置就会推动引擎,从字符串的下一个位置开始尝试,然后是下一个,再下一个,如此继续.不过,如果某个正则表达式是以"字符串起始位置锚点"开始的,传动装置就会知道,不需要更多的尝试,因为如果能够匹配,结果肯定是从字符串的头部开始的.

2.引擎的构造

<1>文字文本: 如a、*、!、枝... 对于非元字符的文字字符,尝试匹配时需要考虑的就是"这个字符与当前尝试的字符是否相同".如果一个正则表达式只包含纯文本字符,如:"usa",那么正则引擎会将其视为:一个"u",接着一个"s",接着一个"a".

<2>字符组、点号、Unicode属性及其它 通常这一节的匹配是比较简单的:不论字符组的长度是多少,它都只能匹配一个字符.点号几乎能匹配任何字符.

<3>捕获型括号 用于捕获文本的括号(而并非用于分组)不会影响匹配的过程.

<4>锚点--eg:^ \z (?<=\d)... 锚点可以分为两大类:简单锚点(^ $ \G \b...)和复杂锚点(环视).

<5>非"电动"括号、反向引用和忽略优先量词 只有NFA引擎支持这些特性,而DFA引擎不支持.

四.标准量词是匹配优先的

标准匹配量词的结果"可能"并非所有可能中最长的,但是它们总是尝试匹配尽可能多的字符,直到匹配上限为止.如果匹配结果并非该表达式的所有可能中最长的,原因肯定是匹配字符过多导致匹配失败.

例如: 用"\b\w+s\b"来匹配包含"s"的字符串"regexes","\w+"完全能够匹配整个单词,但如果用\w+来匹配整个单词,"s"就无法匹配了.为了完成匹配,"\w+"必须只能匹配"regexe",把最后的"s\b"释放(交还)出来.或者说"s"强迫"\w+"将"s\b"释放出来.

如果表达式的其它部分能够匹配的唯一条件是:匹配优先的结构不匹配任何字符,在容许零匹配(如* ?等)的情况下是没问题的.不过,这种情况只有在表达式的后续部分强迫下才能发生.匹配优先量词之所以得名,是因为它们总是(或者,至少是尝试)匹配多于匹配成功下限的字符.

1.过度的匹配优先

"^.*([0-9][0-9])"或许是一个有用的正则表达式,它能够匹配一行字符的最后两位数字,如果有的话,将他们存储到"$1"中.

下面是匹配过程: "."首先匹配整行,而"[0-9][0-9]"是必须匹配的,在尝试匹配行末的时候会失败,这样它会通知".":"你占用的太多了,交出一些字符来吧,这样或许我能匹配".匹配优先组件首先会匹配尽可能多的字符,但为了整个表达式的匹配,它们通常需要"释放"一些字符(克制本能).当然,它们并不"愿意"这样做,只是不得已而为之.当然,"交还"绝不能破坏匹配的成立的必须条件,比如"+"的第一次匹配.

分析正则表达式"^.*([0-9][0-9])"匹配字符串"about 24 characters long"的过程:

".*"匹配整个字符串以后,第一个"[0-9]"的匹配要求".*"释放一个字符"g"(最后一个字符).但是这并不能让"[0-9]"匹配,所以".*"必须继续"交还字符",接下来"交还"的是"n'.如果循环15次,直到".*"最终释放"4"为止.
此时,即使第一个"[0-9]"能够匹配"4",第二个"[0-9]"仍然不能匹配.为了匹配整个正则表达式,".*"必须再次释放一个字符,这次是"2",由第一个"[0-9]"匹配.现在"4"能够由第二个"[0-9]"匹配,所以整个正则表达式匹配的结果是"about 24","$1"的值是"24".

2.匹配优先---先来先服务

多个匹配优先组件组成的正则表达式中,匹配的原则是---"先来先服务(或者理解为'先到先得')"---只要能保证整个正则的匹配成功(如果能)即可.

例如: 正则表达式"^.*[0-9]+"来匹配字符串"copyright 2003.".其中,"[0-9]+"匹配的结果是什么?答案是"3".匹配过程同上,其它自己想.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!