Delphi本身不支持正则式的
DELPHI6本身没有处理正则表达式的库,只能找第三方库。在选择方面,我的标准是:
1. 不必向开发环境注册控件
2. 接口简单
3. 符合主流的perl式正则语法
4. 专业,至少应该有个看上去专业的专门网站
5. 免费
目前符合以上标准, 比较好的 RegEx 类库有 TRegExpr ( http://www.regexpstudio.com/ )与PerlRegEx ( http://www.regular-expressions.info/ )。
TRegExpr是俄国人做的RE类库,应该说是目前国内最主流的免费RegEx类库了。纯DELPHI写成,支持中文,可以选择安装为开发环境控件,也可直接作为类库单元使用(只有一个主类,一个pas文件)。美中不足是自从2004年后就没有更新了,版本一直是0.9xxx,就是不上1。而且不支持Lookaround语法(前瞻与回溯功能)
PerlRegEx底层是用C的类库,完全符合PCRE标准(兼容Perl的正则表达式)。文件结构比TRegExpr复杂一点,包括一个放底层obj文件的子目录和两个接口.pas文件,实际使用时只需要向项目中添加一个单元(当然也可以注册成为控件)。之前的版本据说对中文支持不够,最新版本我在中文环境下用倒没遇到什么问题。说明文档也声称支持Unicode。
现在我是常备两个这两个类库,但主要还是用PerlRegEx。除了迷信最后更新日期与C的执行效率外。还看中了RegexRubby这个基于同一套C类库的RegEx编写工具,以及PerlRegEx提供了一个study方法,声称可以对正则式做点前期编译,提高执行效率。
=========================================================================
二 使用方法:
解压了PerlRegEx包后,如果不想注册控件,除了PerlRegEx.pas、CHelpers.pas和PCRE目录外,其他的东西可以建个隐藏目录搁置起来(没认真阅读用户协议,不知道能不能随便删。。。)。维持这两个文件与PCRE的目录结构不要变。使用时只需要把PerlRegEx.pas添加进项目,在单元中uses PerlRegEx就可以了。
PerlRegEx提供了TPerlRegEx类。主要用法是:
RegEx : TPerlRegEx;
....
RegEx := TPerlRegEx;
try
RegEx.Subject := '要匹配的正文';
RegEx.RegEx := '正则表达式';
if RegEx.Match then ....
finally
RegEx.free
end;
如果要多次匹配并做一些处理,可以:
Matched : boolean;
....
RegEx.Match;
while RegEx.FoundMatch do
begin
....
RegEx.MatchAgain;
end;
如果要替换匹配到的内容,可以
RegEx.Subject := '要匹配的正文';
RegEx.RegEx := '正则表达式';
RegEx.Replace := '替换的字符串'
if RegEx.Match then RegEx.ReplaceAll; //结果在RegEx.subject
或者 if RegEx.Match then Result := RegEx.Replacement;
匹配到的字符串放在RegEx.MatchedExpression中,长度在RegEx.MatchedExpressionLength中,上一次匹配的结束位置在RegEx.Stop中
匹配到的子串放在RegEx.SubExpressions中,子串个数在RegEx.SubExpressionCount中。
如果正则式很复杂而且常用,可创建一个生存期相对长的TPerlRegEx实例.设置好RegEx属性后,使用.Study方法对正则表达式进行预处理.据帮助文档说,文档资料会大大提高效率.
详情可参考文档。有一点文档上没有提到(又或者我看漏了),在第一次匹配之后,如果没有重新赋值subject,下一次匹配无论用Match或者MatchAgain,都是从上次的结束位置开始。所以如果要重新开始匹配,应先把RegEx.Start := 0;
==========================================================================
三. 使用和编写正则表达式要点
使用正则表达式,通常是用作三种用途:校验字符串,提取信息,处理字符串.
当用作校验时,通常是对正文整体校验,例如通常是判断正文是否正确的邮件地址,而不是判断正文是否含有正确的邮件地址.因此应在正则表达式的两端加上行开始锚点^与行结束锚点$.如果待校验的文字允许两端有空格,则应该在锚点前后用' *'或'\s*'(允许空格与TAB)匹配进去.
设计正则表达式的要点在于分段.对要匹配的内容分好段,就能够容易地各个击破.通常在要匹配的文字中会有一些分段的提示,例如逻辑上的单位、重复出现的模式或者不能连续重复出现的字符(串)。
以设计校验输入数字的正则条件为例,可以先列出符合条件的情况:
1234 / 12.34 / -12.34 / 12.3e4 / 12.3e-4 / .12E-34
可以看出,逻辑上的单位有:符号,整数部分,小数点,小数部分,e(或E),指数符号,指数部分
技术上的分段标志有:
符号:在开始与E后面各可能出现一次
小数点:只能出现一次,若出现,其后必须有小数部分。
e:只能出现一次,若出现,其后必须有指数部分。
所有“若出现,其后必须有。。。”的都可以考虑分为一组。可得初步方案: [+\-]?\d*(\.\d+)?([Ee][+\-]*\d+)?
但这个设计有问题,前半段的 \d*(\.\d+)? 是可以匹配空串的,而需求是如果有整数部分,则小数部分可选。如果无整数部分,则必须有小数部分,直观的做法是改为(\d+(\.\d+)?|\.\d+)。再认真观察一下,可以发现这个选择式无论任何情况,都是以\d+结尾,而我们实际上并不关心这个\d+是匹配到整数部分还是小数部分,至于前面的小数点与整数部分都是可选的。因此,这部分可以改写为 \d*\.?\d+
所以最终的校验式是:^ *[+\-]?\d*\.?\d+([Ee][+\-]*\d+)? *$
使用正则表达式提取信息是一个难点,但也是体现正则表达式强大实力的一个方面。提取信息的正则表达式必须要考虑四个方面:不误判(应该有一定语法检验能力),不漏判,子串能匹配到正确位置。一些结构复杂或具有循环结构的正文,可能需要多次处理或使用开发语言的循环结构来辅助提取。具体技巧我现在还觉得比较模糊,以下仅举几个例子:
1. 查找并分析 XX1>XX2<XX3<=XX4=XX5 这样的简写不等式,其中XXn是不包括>,<,=,!,空格,TAB符号的任何字符串,式子两端与元素之间允许有空格或TAB
由于这个不等式可能在上下文中,我们需要先在正文中把合语法的不等式隔离出来,否则下面的循环部分就会匹配到下一条不等式的部分。在这个例子中还算简单,找到 '\b[^<>=!\s]+((不等符号)[^<>=!\s]+)+\b' 就可以了(其中不等符号在下面解释)[1] [2] 下一页