2013-02-19 2 views
1

Я пытаюсь написать регулярное выражение, чтобы извлечь текст списка URL-адресов из источника HTML href и anchor. Текст anchor может быть любым значением.Как я могу проанализировать этот HTML-код с регулярным выражением?

HTML, часть идет следующим образом:

<div class="links"><a rel="nofollow" target="_blank" href="http://url1.com" class="get-all">URL1</a><a rel="nofollow" target="_blank" href="http://url2.com" class="get-all">This is Url-2</a><a rel="nofollow" target="_blank" href="http://url3.com" class="get-all">This is Url-3</a><a rel="nofollow" target="_blank" href="http://url4.com" class="get-all">Sweet URL 4</a></div> 

Я попробовал следующее регулярное выражение, но это не работает, так как она захватывает все до </a> тега и выходит из строя.

preg_match_('/<a rel="nofollow" target="_blank" href="(.*)" class="see-all">(.*)<\/a>/', $source , $website_array); 

Что было бы регулярным выражением для извлечения моих необходимых данных?

+1

Почему вы просто не разобрать HTML? – Blender

+8

http: // stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contains-tags # answer-1732454 Не используйте регулярное выражение для оценки HTML, вместо этого проанализируйте его. Самый простой ответ: HTML не является обычным языком. – KingCrunch

+0

Ребята, я получаю ваш «Dont использовать Regex для разбора HTML», но это очень простая проблема. Я не хочу менять весь свой код, чтобы не использовать Regexp. –

ответ

6

Если вы знаете, выражение жадное, поэтому оно, скорее всего, будет соответствовать началу первого якоря и концу последнего; модификатор /U зафиксирует, что:

preg_match('/<a rel="nofollow" target="_blank" href="(.*)" class="see-all">(.*)<\/a>/U', $source , $website_array); 

Обратите внимание, что pcre.backtrack_limit относится к ungreedy режиму.

Использование наборов прогнозные может дать лучшую производительность:

preg_match('/<a rel="nofollow" target="_blank" href="([^"]*)" class="see-all">([^<]*)<\/a>/', $source , $website_array); 

Это будет иметь проблемы с тегами внутри самого якоря.

С вышеупомянутыми ограничениями, я бы серьезно рассмотреть вопрос об использовании HTML-парсер:

$d = new DOMDocument; 
$d->loadHTML($source); 
$xp = new DOMXPath($d); 
foreach ($xp->query('//a[@class="see-all"][@rel="nofollow"][@target="_blank"]') as $anchor) { 
    $href = $anchor->getAttribute('href'); 
    $text = $anchor->nodeValue; 
} 

Demo

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

+0

Модификатор/U - именно то, что я искал! –

+1

@PeterLur Пробег может отличаться :) также см. Мой комментарий о настройке предела возврата. –

2

Попробуйте

preg_match_all('/<a[^>]+href="([^"]+)"[^>]*>([^>]+)<\/a>/is', $source , $website_array); 

он будет соответствовать всем ссылкам и возвращать массив с информацией. Примечания:

[^ «] - соответствует любому символу, кроме»

1

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

В вашем случае, вы можете попробовать:

$pattern = '#<a rel="nofollow" target="_blank" href="(.*)" class="get-all">(.*)</a>#U'; 
preg_match_all($pattern, $source, $website_array); 

Обратите внимание на ungreedy модификатор (U) в конце. Это очень важно, чтобы соответствовать наименьшему совпадению.

0

В качестве альтернативы вы можете сделать это следующим образом:

<?php 
$html = <<<HTML 
<div class="links"><a rel="nofollow" target="_blank" href="http://url1.com" class="get-all">URL1</a><a rel="nofollow" target="_blank" href="http://url2.com" class="get-all">This is Url-2</a><a rel="nofollow" target="_blank" href="http://url3.com" class="get-all">This is Url-3</a><a rel="nofollow" target="_blank" href="http://url4.com" class="get-all">Sweet URL 4</a></div> 
HTML; 


$xml = new DOMDocument(); 
@$xml->loadHTML($html); 

$links=array(); 
$i=0; 
//Get all divs 
foreach($xml->getElementsByTagName('div') as $divs) { 
    //if this div has a class="links" 
    if($divs->getAttribute('class')=='links'){ 
     //loop through this div 
     foreach($xml->getElementsByTagName('a') as $a){ 
      //if this a tag dose not have a class="get-all" continue to next 
      if($a->getAttribute('class')!='get-all') 
      continue; 

      //Assign values to the links array 
      $links[$i]['href']=$a->getAttribute('href'); 
      $links[$i]['value']=$a->nodeValue; 
      $i++; 
     } 

    } 
} 

print_r($links); 
/* 
Array 
(
    [0] => Array 
     (
      [href] => http://url1.com 
      [value] => URL1 
     ) 

    [1] => Array 
     (
      [href] => http://url2.com 
      [value] => This is Url-2 
     ) 

    [2] => Array 
     (
      [href] => http://url3.com 
      [value] => This is Url-3 
     ) 

    [3] => Array 
     (
      [href] => http://url4.com 
      [value] => Sweet URL 4 
     ) 

) 
*/ 
?> 
Смежные вопросы