Регулярное выражение соответствует полной гиперссылке только с определенным классом - PullRequest
1 голос
/ 30 мая 2011

У меня есть строка с некоторыми гиперссылками внутри. Я хочу сопоставить с регулярным выражением только определенную ссылку из всех них. Я не могу знать, если href или класс идет первым, это может измениться. Это, например, жало:

<div class='wp-pagenavi'>
<span class='pages'>Page 1 of 8</span><span class='current'>1</span>
<a href='http://stv.localhost/channel/political/page/2' class='page'>2</a>     
<a href='http://stv.localhost/channel/political/page/3' class='page'>3</a>ccccc<a href='http://stv.localhost/channel/political/page/4' class='page'>4</a><a href='http://stv.localhost/channel/political/page/5' class='page'>5</a><a href="http://stv.localhost/channel/political/page/2" class="nextpostslink">»eee</a><span class='extend'>...</span><a href='http://stv.localhost/channel/political/page/8' class='last'>lastן »</a>
<a class="cccc">xxx</a>
</div>

Я хочу выбрать из строки aboce только ту, которая имеет класс nextpostslink Таким образом, совпадение в этом примере должно возвращать это -

<a href="http://stv.localhost/channel/political/page/2" class="nextpostslink">»eee</a>

Это регулярное выражение - самое близкое, которое я мог получить -

/<a\s?(href=)?('|")(.*)('|") class=('|")nextpostslink('|")>.{1,6}<\/a>/

Но он выбирает ссылки в начале строки. Я думаю, что моя проблема в (. *) , но я не могу понять, как изменить это, чтобы выбрать только необходимую ссылку.

Буду признателен за вашу помощь.

Ответы [ 5 ]

3 голосов
/ 30 мая 2011

Для этого гораздо лучше использовать настоящий HTML-парсер. Откажитесь от всех попыток использовать регулярные выражения в HTML.

Вместо PHP используйте DOMDocument:

$dom = new DOMDocument;
$dom->loadHTML($yourHTML);

foreach ($dom->getElementsByTagName('a') as $link) {
    $classes = explode(' ', $link->getAttribute('class'));

    if (in_array('nextpostslink', $classes)) {
        // $link has the class "nextpostslink"
    }
}
0 голосов
/ 30 мая 2011

Не уверен, что это то, чем вы являетесь, но в любом случае: плохая идея разбирать html с помощью регулярных выражений. Используйте реализацию xpath для достижения желаемых элементов. Следующее выражение xpath даст вам все элементы 'a' с классом "nextpostlink":

//a[contains(@class,"nextpostslink")]

Вокруг много информации о xpath, так как вы не упомянули свой язык программирования, здесь приведено краткое руководство по xpath с использованием java: http://www.ibm.com/developerworks/library/x-javaxpathapi/index.html

Edit:

php + xpath + html: http://dev.juokaz.com/php/web-scraping-with-php-and-xpath

0 голосов
/ 30 мая 2011

Как бы вы ни старались, невозможно создать безошибочный анализатор HTML, используя только регулярные выражения (исключая тривиальные задачи или проблемы с ОЧЕНЬ ограниченным набором ввода (без вложенных тегов, без одинарных кавычек в двойных кавычках и т. Д.) ).

http://www.codinghorror.com/blog/2009/11/parsing-html-the-cthulhu-way.html

0 голосов
/ 30 мая 2011

Я заменил (. *) На [^ '"] + следующим образом:

<a\s*(href=)?('|")[^'"]+('|") class=('|")nextpostslink('|")>.{1,6}</a>

Примечание: я пробовал это с приятелем RegEx, поэтому мне не нужно было экранировать <> или /

0 голосов
/ 30 мая 2011

Это будет работать в php:

/<a[^>]+href=(\"|')([^\"']*)('|\")[^>]+class=(\"|')[^'\"]*nextpostslink[^'\"]*('|\")[^>]*>(.{1,6})<\/a>/m

Это, конечно, при условии, что атрибут class всегда идет после атрибута href.

Это фрагмент кода:

$html = <<<EOD
<div class='wp-pagenavi'>
<span class='pages'>Page 1 of 8</span><span class='current'>1</span>
<a href='http://stv.localhost/channel/political/page/2' class='page'>2</a>     
<a href='http://stv.localhost/channel/political/page/3' class='page'>3</a>ccccc<a href='http://stv.localhost/channel/political/page/4' class='page'>4</a><a href='http://stv.localhost/channel/political/page/5' class='page'>5</a><a href="http://stv.localhost/channel/political/page/2" class="nextpostslink">»eee</a><span class='extend'>...</span><a href='http://stv.localhost/channel/political/page/8' class='last'>lastן »</a>
<a class="cccc">xxx</a>
</div>
EOD;

$regexp = "/<a[^>]+href=(\"|')([^\"']*)('|\")[^>]+class=(\"|')[^'\"]*nextpostslink[^'\"]*('|\")[^>]*>(.{1,6})<\/a>/m";

$matches = array();
if(preg_match($regexp, $html, $matches)) {
    echo "URL: " . $matches[2] . "\n";
    echo "Text: " . $matches[6] . "\n";
}

Однако я бы предложил сначала сопоставить ссылку, а затем получить URL-адрес, чтобы порядок атрибутов не имел значения:

<?php

$html = <<<EOD
<div class='wp-pagenavi'>
<span class='pages'>Page 1 of 8</span><span class='current'>1</span>
<a href='http://stv.localhost/channel/political/page/2' class='page'>2</a>     
<a href='http://stv.localhost/channel/political/page/3' class='page'>3</a>ccccc<a href='http://stv.localhost/channel/political/page/4' class='page'>4</a><a href='http://stv.localhost/channel/political/page/5' class='page'>5</a><a href="http://stv.localhost/channel/political/page/2" class="nextpostslink">»eee</a><span class='extend'>...</span><a href='http://stv.localhost/channel/political/page/8' class='last'>lastן »</a>
<a class="cccc">xxx</a>
</div>
EOD;

$regexp = "/(<a[^>]+class=(\"|')[^'\"]*nextpostslink[^'\"]*('|\")[^>]*>(.{1,6})<\/a>)/m";

$matches = array();
if(preg_match($regexp, $html, $matches)) {
    $link = $matches[0];
    $text = $matches[4];

    $regexp = "/href=(\"|')([^'\"]*)(\"|')/";
    $matches = array();
    if(preg_match($regexp, $html, $matches)) {
        $url = $matches[2];

        echo "URL: $url\n";
        echo "Text: $text\n";
    }
}

Конечно, вы можете расширить регулярное выражение насоответствует одному из обоих вариантов (сначала класс, сначала класс href), но это будет очень долго, и я не думаю, что это приведет к увеличению производительности.

Так же, как подтверждение концепции, я создал регулярное выражение, которое нене заботьтесь о заказе:

/<a[^>]+(href=(\"|')([^\"']*)('|\")[^>]+class=(\"|')[^'\"]*nextpostslink[^'\"]*(\"|')|class=(\"|')[^'\"]*nextpostslink[^'\"]*(\"|')[^>]+href=(\"|')([^\"']*)('|\"))[^>]*>(.{1,6})<\/a>/m

Текст будет в группе 12, а URL будет в или группе 3 или группе 10 в зависимости от заказа.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...