通分析过了Snoopy类,它里面有比较完善的匹配源码,可以看到有function fetchlinks($URI)。也就是获取”< a >”中链接的函数,可以很简单的提取出来,此外还发现,它的正则还支持高级语言中的三目运算,函数及示例如下:

 1<?php
 2function _striplinks($document) {
 3    preg_match_all("'<s*as.*?hrefs*=s*(["'])?(?(1) (.*?)\1 | ([^s>]+))'isx", $document, $links);
 4    // catenate the non-empty matches from the conditional subpattern
 5    while (list($key, $val) = each($links[2])) {
 6        if (!empty($val))
 7            $match[] = $val;
 8    } while (list($key, $val) = each($links[3])) {
 9        if (!empty($val))
10            $match[] = $val;
11    }
12    // return the links
13    return $match;
14}
15$document = file_get_contents('http://www.qq.com');
16$datalink = _striplinks($document);
17printf("<p>输出link数据为:</p>%sn", var_export($datalink , true));
18?>

以上函数及例子中对源码去掉了注释,通过执行发现很容易就得到了链接部分。下面对上面的正则部分做下解析:

1正则分析:`]+))`'
2
3(\["'\])?                    # 匹配单引或双引号为分组1,也可以没有
4(?(1) (.\*?)\\1 | (\[^s>\]+)) # 如果引号存在(分组1存在)匹配后引号否则匹配非空格和非>内容

这个正则的难点也就是 (xxx)? (?(分组号) yyy|zzz)

我也是第一次碰到这样的正则,有点像高级语言的三目运算,我举个例子:

这个例子的目的是查找符合以下的规则

1、以123开头
2、后面有双引号则匹配引号和引号内的内容。
3、后面没有双引号,则是匹配后面为789的内容。

简单来说是匹配123″……” 或 123789

有引号优先匹配

 1<?php
 2$str = '123"456"789';
 3$search = '/123(")?(?(1).*?\1|789)/';
 4preg_match($search,$str,$r);
 5echo $r[0];
 6//output 123"456"
 7echo '<br /><br />';
 8$str = '123456789';
 9$search = '/123(")?(?(1).*?\1|789)/';
10preg_match($search,$str,$r);
11echo $r[0];
12//output NULL
13echo '<br /><br />';
14$str = '123789456';
15$search = '/123(")?(?(1).*?\1|789)/';
16preg_match($search,$str,$r);
17echo $r[0];
18//output 123789
19?>

从以上示例可以看到,

格式就像三目运算,高级语言是这样的:

(xxx)? yyy : zzz 如果xxx为真 执行yyy,否则执行zzzz

在正则中是:

(xxx)? (?(分组号) yyy|zzz) 如果xxx不为空 执行yyy,否则执行zzzz