正则表达式的逻辑关系

在构造和理解正则表达式的过程中,通常都是由简到繁的过程,如果理解正则表达式内部间的关系,就可以把比较复杂的正则表达式拆分成几个小块来理解,从而帮助消化。

正则表达式的逻辑关系

正则表达式之间的逻辑关系可以简单地用与、或、非来描述,如表所示。

示例

通常来说,正则表达式可以看做这三种逻辑关系的组合。下面分析这三种逻辑。

1.与

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

abc

表示同时出现a、b、c三个字符。

连续字符是“与”关系的最佳代表。此外,有些环视结构也可以表达“与”关系。比如顺序肯定环视(?=exp)表示自身出现的位置后面能匹配表达式exp,换而言之,就是在它后面必须出现表达式exp。例如:

\w+(?=ing)

表示单词的后面必须是ing结尾。
除了顺序肯定环视外,逆序肯定环视也能表达“与”关系。

比如匹配DIV标签里的内容,例如<div>logo</div>中的logo,就可用以下正则表达式来匹配:

(?<=div>).*(?=</div>)

(?<=div>) 表示自身(即要匹配的部分)出现的位置前面匹配表达式”<div>” ,(?=</div>) 表示它后面需要匹配的表达式”</div>“,中间的”.*”就是匹配到的内容。

2.或

“或”是正则表达式中容易出现的逻辑关系。
如果“或”代表元素可以出现,也可以不出现,或者出现的次数不确定,可以用量词来表示“或”关系。比如以下表达式表示在此处,字符a可以出现,也可以不出现:

a?

以下表达式表示在此处,字符串ab必然要出现1次,也可以出现无限多次:

(ab)+

如果“或”表示出现的是某个元素的一个,那么可以使用字符组。比如以下正则表达式表示此处出现的字符是a、b、c中的任何一个:

[abc]

如果要匹配多个字符,则使用分支结构(……|……)。比如匹配单词foot及其复数形式,就可以用正则表达式:

f(oo|ee)t

或者使用如下形式

f[oe]{2}t

3.非

提到”非”,最容易想到正则表达式中的反义和”^”元字符。比如\d表示数字,那么其对应的\D就表示非数字;[a]表示a字符,那么[^a] 就表示这个字符不是a。

“非”关系最常用来匹配成对的标签,例如双引号字符串的匹配,首位两个双引号很容易匹配,其中的内容肯定不是双引号(暂不考虑转义的情况),所以用[^"] 表示,其长度不确定,用*来限定,所以整个表达式如下:

[^"]*

比如,需要匹配HTML里成对的A标签,先匹配左尖括号,紧接着是a字符,后面可以是任意内容,最后是一个右尖括号。在这对括号之间可以出现空格、字母、数字、引号等字符,但是不能出现“>”字符,于是就可以用排除型字符组“[^>]”来表示。再加上后面的配对标签,整个表达式如下:

<a[^>]*>.*<\/a>

运行下面这段代码验证这个表达式:

<?php
$reg = "#<a[^>]*>(.*)<\/a>#";
$str = '<a href="http://baidu.com">baidu</a>---<a href="http://sohu.com">sohu</a>';
preg_match_all($reg, $str, $m);
print_r($m);

运行结果:

Array
(
    [0] => Array
        (
            [0] => <a href="http://baidu.com">baidu</a>---<a href="http://sohu.com">sohu</a>
        )

    [1] => Array
        (
            [0] => baidu</a>---<a href="http://sohu.com">sohu
        )

)

发现结果不符合预期,出现了嵌套匹配。原因在于A标签之间的文本忘了做排除型匹配,于是修改后的正则表达式就成了<a[^>]*>([^<>]*)<\/a>。经过修改后就符合预期了。

<?php
$reg = "#<a[^>]*>([^<>]*)<\/a>#";
$str = '<a href="http://baidu.com">baidu</a>---<a href="http://sohu.com">sohu</a>';
preg_match_all($reg, $str, $m);
print_r($m);

运行结果为:

Array
(
    [0] => Array
        (
            [0] => <a href="http://baidu.com">baidu</a>
            [1] => <a href="http://sohu.com">sohu</a>
        )

    [1] => Array
        (
            [0] => baidu
            [1] => sohu
        )

)

注:上述例子也可以使用前一篇博文中讲过的懒惰匹配。修改正则如下:

<a[^>]*>(.*?)<\/a>

除了反义和排除型字符组外,否定环视也能表示“非”这种关系。比如有一串文字:“ab<p>onecde<div>fgh</div><img src=”“>”。现在需要匹配除P标签外的所有标签。换而言之,就是先匹配所有HTML标签,可以使用如下表达式:

</?\b[^>]+>

匹配闭合的“<XXX>”或“</XXX>”标签,然后再排除“XXX”或“/XXX”部分是P的标签,于是使用顺序否定环视,用表达式:

(?!/?p\b)

排除了“<”或“</”这个位置后是P字符的情况,这样就满足需求了。最终的表达式则为:

<(?!/?p\b)[^>]+>

通过上面的分析得到正则表达式中的“与或非”关系及其代表语法,如表所示。

示例

  • 6
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值