正则表达式的基本概念和原理

元字符(metacharacter)

正则引擎保留字符,作为一般字符匹配时需要转义

流派(flavor)

不同工具支持的元字符和特性各不相同,构成正则表达式的不同流派。

子表达式(subexpression)

括号内的表达式,常用于获取部分匹配结果

字符(character)

正则表达式的基本构成。需要注意不同编码下字符的意义不同,大多数工具只支持ascii编码的字节匹配,近来有部分工作支持unicode编码匹配。

简记字符(shorthands)

\t \n \r;  \s 与  \S, \w 与 \W, \d 与 \D

\b (\<与\>)

使用特定的语言(perl/java/c++)或工具(vim/grep)时需要关注的基本问题:

1. 支持的元字符号及特性

2. 工具的交互方式(如何操作,以及目标文本类型)

3. 正则引擎的类别  (NFA/DFA)

1.支持的元字符及特性

(1)POSIX 1986 将各种常见流派分为两大类

BREs Basic Regular Expressions (grep)

EREs Extented Regular Expressions (egrep)

现在两者的差异缩小, 基本差异为grep元字符需要转义 \? \+ \|

(2)常用元字符和特性 (枯燥,请翻书)

字符表示: \t \n

字符组表示: [a-z] [[:alpha:]] 

锚点: ^ $ \b

注释: (?#...)

分组、条件判断: (...) {min, max} + ?  

2. 不同工具的交互方式

(1)集成式 perl, awk, 修改直接在目标变量上进行,函数或对象式  java,.net, php, c++,  不修改目标变量,直接传回匹配结果。

(2)工具本身的字符串元字符不同,譬如 字符串"\\t" 传给正则引擎的是 "\t";

(3)对文本编码的支持。如 perl中^.$无法匹配"你"而必须使用^...$ , 而egrep 可以

(4)匹配模式。不区分大小写/是否忽略[]外的空白字符/是否支持. 匹配换行符

(3)正则引擎的分类

表达式主导的NFA(非确定有穷自动机)  (大多数非GNU版本的awk, egrep)和 文本主导的DFA(确定有穷自动机) (perl,php,java,.net)

相同的规则(最左最长规则 )

1. 优先选择最左端的匹配结果。如 a|b 匹配字符串'the b is before a', 匹配成功的是'b'

2. 标准量词优先匹配(? * + {min,max})。 greedy, 尽可能匹配多的字符。如^.*([0-9]+)匹配字符串'copyright 2011.' 时子表达式匹配的是 3

    但DFA取绝对最长,如one(self)?(oneselfsufficient)? 匹配 oneselfsufficient ,DFA匹配整各串, 传统型NFA 匹配oneself

    (| 不是标准量词,也往往是NFA和DFA的区分点 , 传统型NFA使用按序匹配)

不同的规则

1. 匹配方法。NFA只扫描一次表达式,DFA只扫描一次目标文本。to(nite|knight|night) 匹配 tonight, NFA的扫描是确定 to,然后nite, knight, night 依次尝试,即目标文本中的ni被扫描两次, 而DFA则同时纪录所有可能的匹配,同样的例子,扫描到目标文本toni 时,DFA引擎已经记录 to(ni,te | knight | ni,ght) 中两种可能匹配。

    注:这个差异意味这DFA的匹配时间复杂度取决于目标文本的大小,与正则表达式的写法无关。而NFA会多次扫描文本,不同正则表达式写法对匹配性能影响巨大。

2.NFA回溯的两个基本规则

   应该首先选择那个分支? 匹配优先量词(* + ? {min, max})优先选择尝试,忽略优先量词 (*? +? ?? {min, max}?) 优先选择放弃尝试。[真变态啊!:-(] 

   匹配失败后应该选择哪个候选分支? 最后存储的 

   sample: ab?c 匹配 abX

 “|"的顺序匹配陷阱

使用 (0?[1-9] | [12][0-9] | 3[01])匹配 Jan 31

why NFA?

NFA编译时间更快,需要的内存更少

NFA提供反向引用,环视,非优先匹配量词,固化分组

注: POSIX NFA为使用NFA原理,同时需要模拟某些DFA特性(如绝对最长匹配)而做,性能相对较差, 相应的工具也较少。

原文地址:https://www.cnblogs.com/wangshi/p/2291822.html