正则表达式问题:将此模式与硬引号或软引号匹配

时间:2009-05-23 17:16:23

标签: php regex

我有这个锚定位正则表达式工作得很好:

$p = '%<a.*\s+name="(.*)"\s*>(?:.*)</a>%im';

匹配<a后跟零或多个任何内容后跟空格name="

即使一个类或一个id在锚点中的名称前面,它也会抓取名称。

我想补充的是能够在name='上使用单引号(')进行匹配,因为迟早有人会这样做。

显然我可以为此添加第二个正则表达式,但它似乎不够优雅。

任何人都知道如何添加单引号并只使用一个正则表达式?任何其他改进或建议都将非常受欢迎。我可以使用我能得到的所有正则表达式帮助!

非常感谢阅读,

function findAnchors($html) {
    $names = array();
    $p = '%<a.*\s+name="(.*)"\s*>(?:.*)</a>%im';
    $t = preg_match_all($p, $html, $matches, PREG_SET_ORDER);
    if ($matches) {
        foreach ($matches as $m) {
            $names[] = $m[1];
        }
        return $names;
    }
}

5 个答案:

答案 0 :(得分:2)

詹姆斯的评论实际上是一个非常流行的,但用于字符串匹配的错误正则表达式。这是错误的,因为它不允许转义字符串分隔符。鉴于字符串分隔符是'或',以下正则表达式起作用

$regex = '([\'"])(.*?)(.{0,2})(?<![^\\\]\\\)(\1)';

\ 1是起始分隔符,\ 2是内容(减2个字符),\ 3是最后2个字符和结束分隔符。只要转义字符为\且转义字符未被转义,此正则表达式允许转义分隔符。 IE。,

'Valid'
'Valid \' String'
'Invalid ' String'
'Invalid \\' String'

答案 1 :(得分:1)

使用[]匹配字符集:

$p = "%<a.*\s+name=['\"](.*)['\"]\s*>(?:.*)</a>%im";

答案 2 :(得分:1)

试试这个:

/<a(?:\s+(?!name)[^"'>]+(?:"[^"]*"|'[^']*')?)*\s+name=("[^"]*"|'[^']*')\s*>/im

在这里你只需剥去周围的引号:

substr($match[1], 1, -1)

但是使用像DOMDocument这样的真正解析器肯定会比这种正则表达式方法更好。

答案 3 :(得分:1)

您当前的解决方案不会将锚点与“名称”后面的其他属性匹配(例如<a name="foo" id="foo">)。

尝试:

$regex = '%<a\s+\S*\s*name=["']([^"']+)["']%i'; 

这会将'name'属性的内容提取到后引用$1\s*还允许属性之间的换行符 您不需要使用“a”标记的其余部分来完成,因为否定的字符类[^"']+将是懒惰的。

答案 4 :(得分:1)

这是另一种方法:

$rgx='~<a(?:\s+(?>name()|\w+)=(?|"([^"]*)"|\'([^\']*)\'))+?\1~i';

我知道这个问题已经过时了,但是当它刚刚重新浮出水面时,我想到了Cookbook中“空捕捉群体作为复选框”的另一种用法。第一个非捕获组在不情愿的加号(+?)的控制下处理所有“名称=值”对的匹配。如果属性名称按字面意思name,则空组(())不匹配任何内容,则后引用(\1)不再匹配任何内容,从而突破循环。 (后向引导成功,因为组参与了比赛,即使它没有消费任何字符。)

每次在组#2中捕获属性值,覆盖在前一次迭代中捕获的任何内容。 (分支重置构造((?|(...)|(...)))使我们能够“重用”组#2来捕获引号内的值,无论它们是什么类型的引号。)因为循环在名称{{1}之后退出}出现,最终捕获的值对应于该属性。

<强> See a demo on Ideone