(PHP) Regex для поиска конкретного тега href - PullRequest
1 голос
/ 18 июля 2011

У меня есть HTML-документ с n тегами "href" с разными целевыми URL и разным текстом между тегами.

Например:

<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>

Как вы видите, целевые URL переключаются между "d ?, d., D / d ?, d / d." и между тегом может быть html любого типа, который разрешен w3c.

Мне нужно регулярное выражение, которое дает мне все ссылки, которые имеют одну из этих комбинаций в целевом URL: "д ?, д., д / д ?, д / д." и имеет «Lorem» или «тест» между «тегами a» в любой позиции, включая теги sub html.

Мое Регекс до сих пор:

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

Я попытался включить лорем / тест следующим образом:

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

но это будет работать только если я поставлю ". *?" до и после (lorem | test) и это было бы жадным.

Если есть более простой способ с SimpleXml или любым другим анализатором DOM, пожалуйста, дайте мне знать. В противном случае я был бы признателен за любую помощь с регулярным выражением.

Спасибо!

Ответы [ 4 ]

2 голосов
/ 18 июля 2011

Вот, пожалуйста:

<code>$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 '
';

Выход:

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

Функция phXML() основана на моей оболочке DOMDocument / SimpleXML и работает следующим образом:

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 голос
/ 18 июля 2011

Вот регулярное выражение, которое работает:

$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>
0 голосов
/ 18 июля 2011

Будет напечатана только первая и четвертая ссылки, потому что выполнены два условия.

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];    
    }

}
0 голосов
/ 18 июля 2011

Используйте анализатор HTML.Существует множество причин, по которым Regex абсолютно не подходит для анализа HTML.

Вот хороший список их здесь: Надежный и зрелый анализатор HTML для PHP

...