性能与特点

DEELX

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 就可以了:

#include "deelx.h"

由于 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/

在其他平台以及其他编译器下,我们还未进行测试。

如果您在其他的编译器或者其他系统下编译成功或者编译失败了,可以通过 [email protected] 告诉我们,我们将非常感谢。


命名分组

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 个可选表达式中的其中一个。可以用于条件表达式的条件有两种类型:

  1. 指定分组(group)是否进行了捕获。
  2. 文本中当前位置是否可以与指定表达式匹配。

条件表达式的举例及说明:

表达式

条件特点

条件说明

(?(1)yes|no)

条件为数字

分组1如果有捕获,则进行 yes 部分匹配,否则 no 部分

(?(?=a)aa|bbb)

条件为预搜索

如果当前位置右侧是 a,则进行匹配 aa,否则匹配 bbb

(?(xxx)aa|bbb)

不与分组命名吻合

如果不与任何分组命名吻合,则视为 (?=xxx) 相同

(?(name)yes|no)

与分组命名吻合

如果与某分组命名吻合,则视为判断该分组是否进行捕获

补充说明:

  1. 如果表达式为 RIGHTTOLEFT 模式,那么 (?(xxx)aa|bbb)(?(?<=xxx)aa|bbb) 相同。
  2. 如果条件表达式只有一个选择项,那么这个选项是在条件成立时进行匹配。
  3. 如果条件表达式中,使用“|”进行分隔的选项多于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 中不会出现死循环。

 

 

简介

正则语法

编程帮助

示例

下载

表达式工具

 

 

RegExLab.com © 2005 -   All Rights Reserved.