Текущее регулярное выражение должно помочь вам:
<a[^>]*href=["|\']([^"|\']*)["|\'][^>]*>(?:<[^>]+>)*([^<]*)(?:</[^>]+>)*<\/a>
Это будет соответствовать вашему примеру, а также этому примеру:
<a href="/go/bla" rel="sponsored noopener" target="_blank"><span><h1>Test link</h1></span></a>
Однако как насчет этого?
<a href="/go/bla" rel="sponsored noopener" target="_blank"><span><h1>Test <span>link</span></h1></span></a>
Неа! Это ломается. И теперь нам нужно будет go вернуться назад и обернуть свои мысли вокруг тегов внутри тегов с текстом вне этих тегов, чтобы все еще соответствовать, нам придется еще немного разбить его. На этом этапе было бы лучше просто получить список всех тегов a
, а затем выполнить некоторые подстановки для извлечения необходимых данных после факта.
$matches = preg_match_callback('/<a[^>]*?href=(.*?")[^>]*?>(.*?)</a>/i', function($m) {
... more regexes
}
Может быть, лучше рассмотреть используя библиотеку, которая позволяет вам загружать html контент как объекты (во многом как в браузере) и запрашивать результаты, используя что-то вроде xpath.
В PHP вы можете использовать DOM и XPath для загрузки html. Ниже приведен пример.
$doc = new DOMDocument();
$html = <<<EOD
<html>
<body>
<a href="/go/bla" rel="sponsored noopener" target="_blank">Test link</a>
<a href="/go/bla" rel="sponsored noopener" target="_blank"><span>Test link</span></a>
<a href="/go/bla" rel="sponsored noopener" target="_blank"><span><h1>Test <span>link</span></h1></span></a>
</body>
</html>
EOD;
$doc->loadHTML($html);
$xpath = new DOMXpath($doc);
$query = $xpath->query('//a');
if (!is_null($query)) {
foreach ($query as $q) {
print $q->getAttribute('href') . ' - ';
print $q->nodeValue . "\n";
}
}