(PHP)用于查找特定href标记的正则表达式

时间:2011-07-18 00:45:15

标签: php html regex href

我有一个带有“a href”标签的html文档,其中包含不同的目标网址和标记之间的不同文字。

例如:

<a href="http://www.example.com/d?12345abc" name="example"><span ....>lorem ipsum</span></a>
<a href="http://www.example.com/d/d?abc1234" name="example2"><span ....>example</span></a>
<a href="http://www.example.com/d.1234" name="example3">example3</a>
<a href="http://www.example.com/d/d.1234" name="example4"><img ...>test</img></a>
<a href="http://www.example.com/without_d/1234" name="example3">without a d as target url</a>

正如您所看到的,目标网址在“d?,d。,d / d?,d / d”之间切换。在“a tag”之间可能存在w3c允许的任何类型的html。

我需要一个正则表达式,它为我提供了所有在目标网址中具有以下组合之一的链接: “d?,d。,d / d?,d / d。”并且在包含子html标签的任何位置的“a标签”之间都有“Lorem”或“test”。

到目前为止我的正则表达式:

href=[\"\']([^>]*?/[d]+[.|\?][^"]*?[\"\'][^>]*[/]?>.*?</a>)

我试图将lorem / test包括在内:

href=[\"\']([^>]*?/[d]+[.|\?][^"]*?[\"\'][^>]*[/]?>(lorem|test)+</a>)

但这只有在我放“。*?”时才有效。在(lorem |测试)之前和之后,这将是贪婪的。

如果使用SimpleXml或任何其他DOM解析器有更简单的方法,请告诉我。否则,我将不胜感激任何有关正则表达式的帮助。

谢谢!

4 个答案:

答案 0 :(得分:2)

你走了:

$html = array
(
    '<a href="http://www.example.com/d?12345abc" name="example"><span ....>lorem ipsum</span></a>',
    '<a href="http://www.example.com/d/d?abc1234" name="example2"><span ....>example</span></a>',
    '<a href="http://www.example.com/d.1234" name="example3">example3</a>',
    '<a href="http://www.example.com/d/d.1234" name="example4"><img ...>test</img></a>',
    '<a href="http://www.example.com/without_d/1234" name="example3">without a d as target url</a>',
);

$html = implode("\n", $html);
$result = array();
$anchors = phXML($html, '//a[contains(., "lorem") or contains(., "test")]');

foreach ($anchors as $anchor)
{
    if (preg_match('~d[.?]~', strval($anchor['href'])) > 0)
    {
        $result[] = strval($anchor['href']);
    }
}

echo '<pre>';
print_r($result);
echo '</pre>';

输出:

Array
(
    [0] => http://www.example.com/d?12345abc
    [1] => http://www.example.com/d/d.1234
)

phXML()函数为based on my DOMDocument / SimpleXML wrapper,如下所示:

function phXML($xml, $xpath = null)
{
    if (extension_loaded('libxml') === true)
    {
        libxml_use_internal_errors(true);

        if ((extension_loaded('dom') === true) && (extension_loaded('SimpleXML') === true))
        {
            if (is_string($xml) === true)
            {
                $dom = new DOMDocument();

                if (@$dom->loadHTML($xml) === true)
                {
                    return phXML(@simplexml_import_dom($dom), $xpath);
                }
            }

            else if ((is_object($xml) === true) && (strcmp('SimpleXMLElement', get_class($xml)) === 0))
            {
                if (isset($xpath) === true)
                {
                    $xml = $xml->xpath($xpath);
                }

                return $xml;
            }
        }
    }

    return false;
}

我现在懒得不使用此功能,但我相信如果你需要,你可以摆脱它。

答案 1 :(得分:1)

这是一个有效的正则表达式:

$search = '/<a\s[^>]*href=["\'](?:http:\/\/)?(?:[a-z0-9-]+(?:\.[a-z0-9-]+)*)\/(?:d\/)?d[?.].*?>.*?(?:lorem|test)+.*?<\/a>/i';
$matches = array();
preg_match_all($search, $html, $matches);

唯一的问题是它依赖于每个`标签之间有一个换行符。否则它会匹配如下:

<a href="http://www.example.com/d.1234" name="example3">example3</a><a href="http://www.example.com/d/d.1234" name="example4"><img ...>test</img></a>

答案 2 :(得分:0)

使用HTML解析器。有很多理由认为Regex绝对不是解析HTML的解决方案。

这里有一个很好的清单: Robust and Mature HTML Parser for PHP

答案 3 :(得分:0)

仅打印第一个和第四个链接,因为满足两个条件。

preg_match_all('#href="(.*?)"(.*?)>(.*?)</a>#is', $string, $matches);
$count = count($matches[0]);
unset($matches[0], $matches[2]);

for($i = 0; $i < $count; $i++){

    if(
        strpos($matches[1][$i], '/d') !== false 
        &&
        preg_match('#(lorem|test)#is', $matches[3][$i]) == true
    )
    {
        echo $matches[1][$i];    
    }

}