Наличие головной боли в виде регулярных выражений с различными ссылками и разделителями href - PullRequest
1 голос
/ 06 ноября 2010

Итак, я хочу сопоставить следующие структуры ссылок с preg_match_all в php ..

<a garbage href="http://this.is.a.link.com/?query=this has invalid spaces" possible garbage>
<a garbage href='http://this.is.a.link.com/?query=this also has has invalid spaces' possible garbage>
<a garbage href=http://this.is.a.link.com/?query=no_spaces_but_no_delimiters possible garbage>
<a garbage href=http://this.is.a.link.com/?query=no_spaces_but_no_delimiters>

Я могу получить "и" удаленные URL, выполнив

'#<a[^>]*?href=("|\')(.*?)("|\')#is'

или я могу получить все 3, но нет, если в первых двух есть пробелы с:

'#<a[^>]*?href=("|\')?(.*?)[\s\"\'>]#is'

Как я могу сформулировать это так, чтобы оно «подбиралось» и «разделялось потенциальными пробелами, а также правильно кодировало URL-адреса без разделителей.

Ответы [ 5 ]

1 голос
/ 06 ноября 2010

Используйте DOM-парсер.Вы не можете анализировать (x) HTML с помощью регулярных выражений.

$html = <<<END
<a garbage href="http://this.is.a.link.com/?query=this has invalid spaces" possible garbage>
<a garbage href='http://this.is.a.link.com/?query=this also has has invalid spaces' possible garbage>
<a garbage href=http://this.is.a.link.com/?query=no_spaces_but_no_delimiters possible garbage>
<a garbage href=http://this.is.a.link.com/?query=no_spaces_but_no_delimiters>
END;

$domd = new DOMDocument();
libxml_use_internal_errors(true);
$domd->loadHTML($html);
libxml_use_internal_errors(false);

$items = $domd->getElementsByTagName("a");
foreach ($items as $item) {
  var_dump($item->getAttribute("href"));
}
1 голос
/ 06 ноября 2010

РЕДАКТИРОВАТЬ: я отредактировал это, чтобы работать немного лучше, чем я первоначально отправил.

У вас почти есть это во втором регулярном выражении:

'#<a[^>]*?href=("|\')?(.*?)[\\1|>]#is'

Возвращает следующий массив:

array(3) {
  [0]=>
  array(4) {
    [0]=>
    string(92) "<a garbage href="http://this.is.a.link.com/?query=this has invalid spaces" possible garbage>"
    [1]=>
    string(101) "<a garbage href='http://this.is.a.link.com/?query=this also has has invalid spaces' possible garbage>"
    [2]=>
    string(94) "<a garbage href=http://this.is.a.link.com/?query=no_spaces_but_no_delimiters possible garbage>"
    [3]=>
    string(77) "<a garbage href=http://this.is.a.link.com/?query=no_spaces_but_no_delimiters>"
  }
  [1]=>
  array(4) {
    [0]=>
    string(1) """
    [1]=>
    string(1) "'"
    [2]=>
    string(0) ""
    [3]=>
    string(0) ""
  }
  [2]=>
  array(4) {
    [0]=>
    string(74) "http://this.is.a.link.com/?query=this has invalid spaces" possible garbage"
    [1]=>
    string(83) "http://this.is.a.link.com/?query=this also has has invalid spaces' possible garbage"
    [2]=>
    string(77) "http://this.is.a.link.com/?query=no_spaces_but_no_delimiters possible garbage"
    [3]=>
    string(60) "http://this.is.a.link.com/?query=no_spaces_but_no_delimiters"
  }
}

Работает с разделителями или без них.

1 голос
/ 06 ноября 2010

ОК, похоже, это работает:

'#<a[^>]*?href=((["\'][^\'"]+["\'])|([^"\'\s>]+))#is'

($ match [1] содержит URL-адреса)

Единственное раздражение в том, что в указанных URL-адресах все еще включены кавычки, поэтому вам придется их удалить:

$first = substr($match, 0, 1);
if($first == '"' || $first == "'")
    $match = substr($match, 1, -1);
0 голосов
/ 06 ноября 2010

Как указано @JasonWoof, вам нужно использовать встроенную альтернативу: одна альтернатива для цитируемых URL-адресов, другая для не цитируемых.Я также рекомендую использовать группу захвата, чтобы определить, какой тип цитаты используется, как это сделал @DanHorrigan.С добавлением отрицательного взгляда ((?!\\2)) и притяжательных квантификаторов (*+) вы можете создать очень надежное регулярное выражение, которое также очень быстро:

~
<a\\s+[^>]*?\\bhref=
(
  (["'])          # capture the opening quote
  (?:(?!\\2).)*+  # anything else, zero or more times
  \\2             # match the closing quote
|
  [^\\s>]*+   # anything but whitespace or closing brackets
)
~ix

См.это в действии на ideone. (Удвоенные обратные слеши вызваны тем, что регулярное выражение написано в форме heredoc PHP. Я бы предпочел использовать nowdoc, но ideone, очевидно, все еще работает на PHP 5.2.)1010 *

0 голосов
/ 06 ноября 2010

Когда вы говорите, что хотите сопоставить их, вы пытаетесь извлечь информацию из ссылок или просто находите гиперссылки с href?Если вам нужен только последний, это должно работать просто отлично:

/<a[^>]*href=[^\s].*?>/
...