Ограничьте количество результатов, используя preg_match_all PHP - PullRequest
3 голосов
/ 17 декабря 2010

Есть ли способ ограничить количество совпадений, которые будут возвращены с помощью preg_match_all?

Так, например, я хочу сопоставить только первые 20 <p> тегов на веб-странице, но есть100 <p> тегов.

Приветствия

Ответы [ 6 ]

4 голосов
/ 17 декабря 2010

Нет, вычисление набора результатов preg_match_all не может быть ограничено. Вы можете ограничить результаты только с помощью array_slice или array_splice (для этого потребуется PREG_SET_ORDER ):

preg_match_all($pattern, $subject, $matches, PREG_SET_ORDER);
$firstMatches = array_slice($matches, 0, 20);

Но кроме того, вы не должны использовать регулярные выражения для разбора HTML в любом случае. Хотя современные механизмы регулярных выражений больше не являются регулярными и могут обрабатывать нерегулярные языки, такие как HTML, они слишком подвержены ошибкам. Вместо этого лучше использовать соответствующий HTML-анализатор, такой как PHP DOM-библиотека . Тогда просто используйте счетчик, чтобы получить только до 20 матчей:

$doc = new DOMDocument();
$doc->loadHTML($code);
$counter = 20;
$matches = array();
foreach ($doc->getElementsByTagName('p') as $elem) {
    if ($counter-- <= 0) {
        break;
    }
    $matches[] = $elem;
}
3 голосов
/ 17 декабря 2010

Просто сопоставьте все и нарежьте получившийся массив:

$allMatches = array ();
$numMatches = preg_match_all($pattern, $subject, $allMatches, PREG_SET_ORDER);
$limit = 20;
$limitedResults = $allMatches;
if($numMatches > $limit)
{
   $limitedResults = array_slice($allMatches, 0, $limit);
}

// Use $limitedResults here
3 голосов
/ 17 декабря 2010
$matches = array();   
preg_match_all ( $pattern , $subject , $matches );
$twenty = array_slice($matches , 0, 20);
0 голосов
/ 02 октября 2018

Вы можете использовать T-Regx библиотека:

pattern('<p>')->match($yourHtml)->only(20);
0 голосов
/ 17 декабря 2010

Вы можете либо использовать preg_match_all() и отбрасывать совпадения, которые вам не интересны, либо вы можете использовать цикл с preg_match(). Второй вариант будет лучше, если вы беспокоитесь о затратах на сканирование большой строки.

Этот пример ограничивает 2 совпадения, когда на самом деле их всего 3:

<?php

$str = "ab1ab2ab3ab4c";

for ($offset = 0, $n = 0;
        $n < 2 && preg_match('/b([0-9])/', $str, $matches, PREG_OFFSET_CAPTURE, $offset);
        ++$n, $offset = $matches[0][1] + 1) {

        var_dump($matches);
}

Действительно петля while, вероятно, была бы более четкой, чем петля for при отражении;)

0 голосов
/ 17 декабря 2010

Я так не думаю, но preg_match имеет параметр offset, а также флаг PREG_OFFSET_CAPTURE, который в сочетании может использоваться для получения "следующего совпадения".

Это в основном полезно, если вы не хотите получать все результаты, а затем array_slice() часть: o)

EDIT: Хорошо, вот код (не тестировался и не использовался каким-либо образом):

$offset = 0;
$matches = array();
for ($i = 0; $i < 20; $i++) {
    $results = preg_match('/<p(?:.*?)>/', $string, PREG_OFFSET_CAPTURE, $offset);
    if (empty($results)) {
        break;
    } else {
        $matches[] = $results[0][0];
        $offset += $results[0][1];
    }
}
...