我有这个锚定位正则表达式工作得很好:
$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;
}
}
答案 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 强>