DEELX 正则引擎性能与特点
            
            C++ 环境下的正则表达式引擎,RegExLab 的研究开发项目。 
             
            本页内容:
            
             
            使用模板库编写
            DEELX 正则引擎全部采用模板 template 编写,可将 DEELX 用于 char, wchar_t 以及其他基类型,比如 unsigned char, int 等。但只能是简单数据类型,不可以是 struct 或者 union 等复合类型。 
            比如: 
            
              
                
                  #include "deelx.h"
  int pattern[] = {65, 
                  '+', 66, 0}; // 0 to indicate end int text[] = {180000, 
                  65, 65, 66, 0};
  CRegexpT <int> regexp(pattern); MatchResult result = regexp.Match(text); 
                   if(result.IsMatched()) {     printf("start at: %d\nlength: %d\n", result.GetStart(),         result.GetEnd() - result.GetStart()); } | 
                 
               
             
            更多详情可参考: 
            
              [  编程帮助] 
             
             
            从右向左(RIGHTTOLEFT)匹配模式
            DEELX 支持从右向左匹配模式,可使表达式从文本结束位置向前查找匹配。在表达式中,右侧的表达式比左侧的表达式先匹配。编写用来在“从右向左”模式下使用表达式与普通情况下使用的表达式并没有什么不同。匹配次数修饰符(*, +, {n}, ……)仍然位于被修饰部分的右侧;^ 仍然匹配文本开始;正向预搜索 (?=xxx) 仍然是向右搜索,而不是向左;分组(group)编号仍然是从左向右进行编号;等等。 
            需要注意的是,当使用了“从右向左”模式后,右侧的表达式会先进行匹配。这时如果使用了反向引用,那么被引用的分组(group)应该是在右侧。 
            比如: 
            
              
                
                  | 
                   “从右向左”模式下  | 
                  
                   正常模式下  | 
                 
                
                  | 
                   \2(.*?)('|") 
                   | 
                  
                   ('|")(.*?)\1 
                   | 
                 
               
             
            递归匹配没有这个限制,不管是否是“从右向左”模式,下边的两种写法都是可以的: 
            
              
                
                  | 
                   (?2)(.*?)(") 
                   | 
                 
                
                  | 
                   (")(.*?)(?1) 
                   | 
                 
               
             
             
            反向预搜索(反向零宽度断言)
            “反向预搜索”就是在匹配过程中,要求当前位置左侧的文本必须符合某个条件,格式为 (?<=xxx) 或者 (?<!xxx)。与 \b 类似,本身不匹配任何文本,只是对该当前位置设置一个条件。比如: 
            
              
                
                  | 
                   表达式  | 
                  
                   说明  | 
                 
                
                  | 
                   \b  | 
                  
                   要求当前位置为单词的边界,也就是说,左右两侧只能有一侧是字母或数字。  | 
                 
                
                  | 
                   (?<!\w)(?=\w)  | 
                  
                   要求当前位置为单词开头,只能是右侧是字母或数字。  | 
                 
                
                  | 
                   (?<=\w)(?!\w)  | 
                  
                   要求当前位置为单词结尾,只能是左侧是字母或数字。  | 
                 
               
             
            关于反向预搜索中包含的表达式,Perl, Java, GRETA 以及 DEELX 的细节都不相同: 
            
              
                
                  | 
                   引擎  | 
                  
                   说明  | 
                  
                   举例  | 
                 
                
                  | 
                   Perl  | 
                  
                   只能使用固定长度的反向预搜索。  | 
                  
                   (?<=\t)print 
                   | 
                 
                
                  | 
                   Java  | 
                  
                   允许使用不定长度的反向预搜索,但必须要有最大长度。  | 
                  
                   (?<=\{\s{0,100})print 
                   | 
                 
                
                  | 
                   GRETA  | 
                  
                   允许使用没有长度限制,但否定格式存在一些问题。  | 
                  
                   (?<=\{\s*)print 
                   | 
                 
               
             
            DEELX 中的反向预搜索: 
            DEELX 采用 RIGHTTOLEFT 模式来匹配“反向预搜索”中的表达式。使反向预搜索与正向预搜索在逻辑上完全相同,而方向相反。因此,在 DEELX 中,反向预搜索与正向预搜索一样,没有长度限制。 
            比如,在 DEELX 引擎中: 
            
              
                
                  | 
                   文本  | 
                  
                   表达式  | 
                  
                   匹配结果  | 
                 
                
                  | 
                   {print}  | 
                  
                   (?<!\{\s*)print 
                   | 
                  
                   匹配失败  | 
                 
                
                  | 
                   (?<=\{\s*)print 
                   | 
                  
                   匹配成功  | 
                 
               
             
             
            移植简单
            DEELX 全部使用模板库编写,因此没有任何 cpp 或者 lib 文件。全部代码位于一个头文件(deelx.h)中。使用时,不需要为 DEELX 创建 project,也不需要添加任何 cpp 或者静态库 lib 文件。运行时,也不依赖专门的动态库。 
            使用 DEELX 正则引擎时,只需要简单地添加一个 include 就可以了: 
            
              
             
            由于 deelx.h 已经直接包含到你的项目中,因此不会存在 Runtime Library 与主项目不同的问题,也不用担心会产生连接错误的问题。 
             
            兼容性
            DEELX 采用纯 C++ 代码编写,没有使用任何 STL 类或者 MFC 类。DEELX 已测试能够在以下编译器及操作系统中编译: 
            
              
                
                  | 
                   编译器  | 
                  
                   版本  | 
                  
                   操作系统  | 
                  
                   备注  | 
                 
                
                  | 
                   VC++  | 
                  
                   6.0, 7.1, 8.0  | 
                  
                   Windows  | 
                  
                      | 
                 
                
                  | 
                   GCC  | 
                  
                   3.4  | 
                  
                   Cygwin  | 
                  
                      | 
                 
                
                  | 
                   GCC  | 
                  
                   3.4  | 
                  
                   Linux  | 
                  
                      | 
                 
                
                  | 
                   Turbo C++  | 
                  
                   3.0  | 
                  
                   DOS  | 
                  
                      | 
                 
                
                  | 
                   C++ Builder  | 
                  
                   6.0  | 
                  
                   Windows  | 
                  
                      | 
                 
                
                  | 
                   Borland C++  | 
                  
                   5.5  | 
                  
                   Windows  | 
                  
                      | 
                 
                
                  | 
                   GCC  | 
                  
                   2.7  | 
                  
                   FreeBSD 2.2  | 
                  
                      | 
                 
                
                  | 
                   GCC  | 
                  
                   3.4  | 
                  
                   Solaris 10 Unix  | 
                  
                   http://www.unix-center.net/  | 
                 
               
             
            在其他平台以及其他编译器下,我们还未进行测试。 
            如果您在其他的编译器或者其他系统下编译成功或者编译失败了,可以通过 regexlab@gmail.com 告诉我们,我们将非常感谢。 
             
            命名分组
            DEELX 支持 Python 及 .NET 风格的命名分组。命名分组的编号顺序按照 .NET 风格。DEELX 支持以下格式的命名分组: 
            
              
                
                  | 
                   表达式  | 
                  
                   风格  | 
                  
                   说明  | 
                 
                
                  | 
                   (?P<the_name>xxxx) 
                   | 
                  
                   Python  | 
                  
                   定义一个命名 'the_name' 的命名分组  | 
                 
                
                  | 
                   (?<the_name>xxxx)  | 
                  
                   .NET  | 
                 
                
                  | 
                   (?'the_name'xxxx)  | 
                 
               
             
            匹配成功后,可通过分组的命名来获取分组捕获到的内容。 
            DEELX 允许多个命名分组的名字相同,这时它们捕获到的内容会放在同一个分组编号下。在逻辑上,它们是同一个分组,比如: (?<string>".*?")|(?<string>'.*?')
              。如果两个命名相同分组之间有包含关系,那么被包含的那个分组将不进行捕获,比如: (?<number>(?<number>\d+)\.?) 
              。 
            此外,与命名分组相关的功能有:反向引用,递归表达式,条件表达式,以及替换操作。 
            
              
                
                  | 
                   功能  | 
                  
                   表达式  | 
                  
                   风格  | 
                  
                   说明  | 
                 
                
                  | 
                   反向引用  | 
                  
                   \g<the_name>  | 
                  
                   Python  | 
                  
                   反向引用命名分组 'the_name'  | 
                 
                
                  | 
                   \k<the_name>  | 
                  
                   .NET  | 
                 
                
                  | 
                   \k'the_name'  | 
                 
                
                  | 
                   递归表达式  | 
                  
                   (?R<the_name>)  | 
                    | 
                  
                   递归表达式引用命名分组 'the_name'  | 
                 
                
                  | 
                   (?R'the_name')  | 
                 
                
                  | 
                   条件表达式  | 
                  
                   (?(the_name)yes|no)  | 
                  
                   .NET  | 
                  
                   根据分组 'the_name' 是否有捕获  | 
                 
                
                  | 
                   替换操作  | 
                  
                   ${the_name}  | 
                  
                      | 
                  
                   替换时,表示分组 'the_name' 的内容  | 
                 
               
             
             
            条件表达式
            条件表达式就是根据某个条件是否成立,来选择匹配 2 个可选表达式中的其中一个。可以用于条件表达式的条件有两种类型: 
            
              - 指定分组(group)是否进行了捕获。
 
              - 文本中当前位置是否可以与指定表达式匹配。
 
             
            条件表达式的举例及说明: 
            
              
                
                  | 
                   表达式  | 
                  
                   条件特点  | 
                  
                   条件说明  | 
                 
                
                  | 
                   (?(1)yes|no)  | 
                  
                   条件为数字  | 
                  
                   分组1如果有捕获,则进行 yes 部分匹配,否则 no 部分  | 
                 
                
                  | 
                   (?(?=a)aa|bbb)  | 
                  
                   条件为预搜索  | 
                  
                   如果当前位置右侧是 a,则进行匹配 aa,否则匹配 bbb  | 
                 
                
                  | 
                   (?(xxx)aa|bbb)  | 
                  
                   不与分组命名吻合  | 
                  
                   如果不与任何分组命名吻合,则视为 (?=xxx)
                  相同  | 
                 
                
                  | 
                   (?(name)yes|no)  | 
                  
                   与分组命名吻合  | 
                  
                   如果与某分组命名吻合,则视为判断该分组是否进行捕获  | 
                 
               
             
            补充说明: 
            
              - 如果表达式为 RIGHTTOLEFT 模式,那么 (?(xxx)aa|bbb) 
                与 (?(?<=xxx)aa|bbb)
                相同。
 
              - 如果条件表达式只有一个选择项,那么这个选项是在条件成立时进行匹配。
 
              - 如果条件表达式中,使用“|”进行分隔的选项多于2个,则只有第一个“|”被视为条件表达式选项分隔符。比如: (?(?=xxx)yes|no1|no2),条件成立时,匹配 
              yes 部分,否则匹配 "no1|no2"。
 
             
             
            递归表达式
            “递归表达式”就是对另一部分子表达式本身的引用,而不是对其匹配结果的引用。举例说明: 
            
              
                
                  | 
                   表达式  | 
                  
                   等效的表达式1  | 
                  
                   等效的表达式2  | 
                  
                   可以匹配  | 
                 
                
                  | 
                   (\w)(?1)  | 
                  
                   (\w)(\w)  | 
                  
                      | 
                  
                   ab  | 
                 
                
                  | 
                   (?1)(\w(?2))(\d)  | 
                  
                   (?1)(\w(\d))(\d)  | 
                  
                   (\w(\d))(\w(\d))(\d)  | 
                  
                   a1b23  | 
                 
               
             
            如果被引用的表达式又包含自身,则形成了递归引用。举例说明: 
            
              
                
                  | 
                   表达式  | 
                  
                   等效1  | 
                  
                   等效2  | 
                  
                   可以匹配  | 
                 
                
                  | 
                   (\w(?1)?) 
                   | 
                  
                   (\w(\w(?1)?)?)  | 
                  
                   (\w+)  | 
                  
                   ghjk5……  | 
                 
                
                  | 
                   \(([^()]|(?R))*\)  | 
                  
                   \(([^()]|\(([^()]|(?R))*\))*\)  | 
                  
                      | 
                  
                   (a * (c + 2))  | 
                 
               
             
            递归表达式的格式有: 
            
              
                
                  | 
                   格式  | 
                  
                   说明  | 
                 
                
                  | 
                   (?R)  | 
                  
                   对整个表达式的递归引用。  | 
                 
                
                  | 
                   (?R1),(?R2)  | 
                  
                   对指定分组的递归引用。  | 
                 
                
                  | 
                   (?1),(?2)  | 
                 
                
                  | 
                   (?R<named>)  | 
                  
                   对指定命名分组的递归引用。  | 
                 
                
                  | 
                   (?R'named')  | 
                 
               
             
             
            防止死循环
            能匹配零长度的子表达式,如果在被修饰匹配次数时被修饰为可以匹配任意次,则在很多正则引擎中,容易出现死循环。为此,DEELX 已通过技术手段,防止死循环的出现。 
            比如,容易出现死循环的表达式: 
            
              
                
                  | 
                   表达式  | 
                  
                   说明  | 
                 
                
                  | 
                   (a*)* 
                   | 
                  
                   因 a* 可以匹配零长度,整个表达式可能死循环。但在 DEELX 中不会出现死循环。  | 
                 
                
                  | 
                   (a|b|c?)*  | 
                  
                   其中一个选项可以匹配零长度,也容易出现死循环。但在 DEELX 中不会出现死循环。  | 
                 
               
             
              
             |