正则表达式中的与或非解析

时间:2022-06-15 08:50:34

摘 要:在编写处理字符串的程序或网页时,经常会有查找符合某些复杂规则的字符串的需要。正则表达式就是用于描述这些规则的语法。本文通过与、或、非这三种逻辑运算来阐述正则表达式的正确使用方法。

关键词:正则表达式;与;或;非

中图分类号:TP393.08

正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑。在计算机科学中,是指一个用来描述或者匹配一系列符合某个句法规则的字符串的单个字符串。我们可以归纳为三种逻辑,即与、或、非。

一般来说,正则表达式千变万化,总是这三种逻辑的组合。比如匹配双引号字符串"quoted string"。

与:首尾的双引号字符必须出现。

或:两个双引号之间的字符个数是不确定的(如果是空字符串””,则两个双引号之间没有字符)。

非:两个双引号之间不能出现双引号字符。

再比如匹配html中的open-tag(比如)和close-tag(比如):

与:首尾必须分别是,如果是close-tag,则

或:之间必须出现至少一个字符(不是一个合法的tag)。

非:

下面我们来解析三种逻辑的对策。

1 与

“与”是正则表达式中最普通的逻辑关系。一般来说,如果正则表达式中的元素没有任何量词(quantifier,比如*、?、+)修饰,就是“与”关系。比如『

2 或

“或”是正则表达式中最灵活的逻辑关系。正则表达式能应对各种不同的文本,“或”功能不可或缺。

如果“或”的意思是,元素可以出现,也可以不出现,或者出现的次数不确定,可以用量词来表示“或”关系。比如表达式『a?,表示在此处,字符a可以出现,也可以不出现;表达式『(ab)+,表示在此处,字符串ab必然要出现1次,也可以出现无限多次。

如果“或”的意思是,可以出现的是某几个元素中的一个,则应该使用字符组或者多选结构。当元素都是单个字符时,就应该使用字符组『[…]:比如匹配单词cat或者cut,除去开头的a、结尾的t是固定的,之中“或许出现a,或许出现u”,所以应当使用字符组『[au],整个正则表达式就是『c[au]t。当元素不只单个字符(只要有一个元素不只单个字符)时,就应该使用多选结构『(…|…):比如不但要匹配单词cat或者cut,还要匹配单词chart、conduct和court,除去开头的a、结尾的t是固定的,之中“或许出现a,或许出现u,或许出现har,或许出现onduc,或许出现our”,这时候就应该使用多选结构『(a|u|har|onduc|our),整个正则表达式就是『c(a|u|har|onduc|our)t。

当然,多选分支也可以表示字符组,比如『[au]就可以表示为『(a|u),两者的功能是完全等价的。

在实践中,“与”和“或”经常同时出现,比如这个URL pattern:/foo/bar_tmp.php。foo是模块名,bar是控制器名,tmp是方法名。合法的URL并不要求3个名字每次都出现,可以只出现控制器名(/foo),也可以只出现控制器名和模块名(/foo/bar.php),也可以3者都出现(/foo/bar_tmp.php)。

这里的模块名、控制器名、方法名,都可以用『[a-z]+匹配,我们暂用foo、bar、tmp代替对应的表达式。

与:/foo必须出现。

或:/bar和.php是可选出现的,但必须同时出现,或同时不出现(与)/foo必须出现,这很好表示,暂且不去管它;/bar和.php如果出现,必须同时出现,所以它们应该作为一个元素,写作『(/bar.php);整个元素可选出现,所以给它添加量词,得到『(/bar.php)?;最后,在/bar和.php都出现的前提下,_tmp才可以出现,所以将『(_tmp)?填充到『(/bar.php)?,得到『(/bar(_tmp)?.php)?,最后加上开头的/foo,整个表达式就是『(/bar(_tmp)?.php)?。

3 非

“非”是正则表达式中最难处理的逻辑关系。因为没有直接对应的结构。最简单的“非”,意思是此处不能出现某个字符,似乎用排除型字符组『[^…]就可以解决。我们仍然举cat和cut的例子,如果仍然希望匹配c开头、t结尾的单词,但不希望匹配cut,可以写成『c[^u]t,即:最开头的字母是c,之后是一个不为u的字符,之后是t。没错,它确实不会匹配cut,也可以匹配cat。但是,chart、conduct、court等等,它也没法匹配,因为[^u]的意思是:匹配一个不是u的字符。

分析要实现的功能:

与:以c开头,以t结尾。

或:c和t之间可以出现的字母必须多于一个,没有上限。

非:c和t之间不能只有一个字符u。

在c之间的位置向后看,不能出现cut。这一点,正好对应否定顺序环视(positive look-ahead)功能,『(?!cut)就是用来进行这种判断的,它判断之后的字符串能不能由cut匹配,但并不真正真正进行匹配,也不会移动“当前位置”。所以我们将它放在表达式的最开头,得到『(?!cut)c[a-z]+t。这个表达式的逻辑是:只有在当前位置右侧字符串不能由cut匹配的情况下,才从这里开始,向右尝试用c[a-z]+t。

如果我们更进一步,需要排除掉cat和cut,可以把否定顺序环视改为『(?!c[au]t)。这样就能保证,匹配到的肯定不是cat或者cut。

更复杂一点,如果我们要验证这样一个字符串:它全部由小写字母构成,长度不超过12位,其中不能包含unfavored或者unwanted。也可以照章处理,先匹配“长度不超过12位”的小写字母『[a-z]{,12},然后写出匹配“不需要匹配内容”的正则表达式,『(unfavored|unwanted),再用否定顺序环视将它“排除”即可,只是这次要注意,不能直接写『(?!(unfavored|unwanted)),因为它只能排除『(unfavored|unwanted)出现在字符串开头的情况,为了排除它出现在字符串中的情况,我们要把否定顺序环视改为『(?![a-z]*(unfavored|unwanted)),这样就确保完整的“排除”,整个表达式就是『(?![a-z]*(unfavored|unwanted))[a-z]{,12}。

正则表达式中的“非”,除去能用排除型字符组直接表示的,复杂一点的“非”逻辑都是按照这样的思路进行的:先用一个正则表达式准确匹配需要“排除”的字符串,再用环视功能排除掉它――“非”确实是正则表达式中,最难处理的逻辑关系,好在它并不复杂,而且,除去一些比较古老的工具(比如Apache 1.3),现在各种工具和语言,基本都支持这种功能。

参考文献:

[1]张树壮,罗浩,方滨兴.面向网络安全的正则表达式匹配技术[J].软件学报,2011(08).

[2]钟京馗.JAVA中的正则表达式及其应用[J].电脑编程技巧与维护,2005(06).

[3]杜冬梅,许彩欣,苏健.浅谈正则表达式在web系统中的应用[J].计算机系统应用,2007(08).

[4]邓绪斌,朱扬勇.ReDE:一个基于正则表达式的生物数据抽取方法[J].计算机研究与发展,2005(12).

作者简介:周兴旺(1979.11-),男,扬州人,讲师,硕士,研究方向:计算机网络技术、数据挖掘、教育教学管理等。

作者单位:南通农业职业技术学院,江苏南通 226007

基金项目:江苏高校哲学社会科学研究项目(项目编号:NO.2014SJD641)。

上一篇:RHEL5下vsftpd服务器的配置与研究 下一篇:中间件技术在Web数据库中的应用