使用preg_match_all PHP限制结果数

使用preg_match_all PHP限制结果数,php,regex,preg-match-all,Php,Regex,Preg Match All,有没有办法限制使用preg\u match\u all返回的匹配数 例如,我只想匹配网页上的前20个标签,但有100个标签 干杯否,preg\u match\u all结果集的计算无法限制。您只能使用或限制之后的结果(这需要预设置顺序): 但除此之外,无论如何都不应该使用正则表达式来解析HTML。尽管现代正则表达式引擎不再是正则的,可以处理像HTML这样的不规则语言,但它太容易出错。最好使用适当的HTML解析器,而不是使用其中一个。然后只需使用计数器即可获得最多20个匹配项: $doc = ne

有没有办法限制使用
preg\u match\u all
返回的匹配数

例如,我只想匹配网页上的前20个标签,但有100个标签


干杯

否,
preg\u match\u all
结果集的计算无法限制。您只能使用或限制之后的结果(这需要预设置顺序):

但除此之外,无论如何都不应该使用正则表达式来解析HTML。尽管现代正则表达式引擎不再是正则的,可以处理像HTML这样的不规则语言,但它太容易出错。最好使用适当的HTML解析器,而不是使用其中一个。然后只需使用计数器即可获得最多20个匹配项:

$doc = new DOMDocument();
$doc->loadHTML($code);
$counter = 20;
$matches = array();
foreach ($doc->getElementsByTagName('p') as $elem) {
    if ($counter-- <= 0) {
        break;
    }
    $matches[] = $elem;
}
$doc=newDOMDocument();
$doc->loadHTML($code);
$counter=20;
$matches=array();
foreach($doc->getElementsByTagName('p')作为$elem){

如果($counter--只需匹配全部并对结果数组进行切片:

$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
我不这么认为,但确实有一个
offset
参数,还有一个
PREG\u offset\u CAPTURE
标志,当组合起来时,可以用来获得“下一个匹配”

如果您不想获得所有结果,然后
array\u slice()

编辑: 好的,这里有一些代码(未经测试或以任何方式使用):

$offset=0;
$matches=array();
对于($i=0;$i<20;$i++){
$results=preg_match('/',$string,preg_OFFSET_CAPTURE,$OFFSET);
if(空($results)){
打破
}否则{
$matches[]=$results[0][0];
$offset+=$results[0][1];
}
}

您可以使用
preg\u match\u all()
并放弃您不感兴趣的匹配,也可以使用带有
preg\u match()
的循环。如果您担心扫描大字符串的开销,第二个选项会更好

当整个字符串中实际有3个匹配项时,此示例限制为2个匹配项:

<?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);
}
您可以使用库:

模式(“”)->仅匹配($yourHtml)->(20);

这是正确的答案;是最节省内存的方法。
改为通过
preg\u replace\u callback()
使用引用赋值

<?php

$matches = [];

preg_replace_callback(
    '~<p(?:\s.*?)?>(?:.*?)</p>~s',
    function (array $match) use (&$matches) {
        $matches[] = $match[0];
    },
    $html,
    20,
    $_
);

var_dump($matches);

为了扩展@Gumbo关于使用DOM解析器而不是regex的伟大建议,下面的代码片段将使用带有
position()
条件的XPath查询来限制目标标记

代码:()


干杯Gumbo,这个DOM东西真的很有用。从来没有尝试过在HTML上使用它而不是reg ex,所以会尝试一下!@SiQ:注意,DOMDocument实现了W3C指定的DOM,因此非常广泛;如果你只需要阅读DOM,你也可以尝试。你的DOMDocument解决方案也会限制事后的代码,不是吗oesn没有设置限制,但会忽略它收集的额外标记。当p标记具有属性或其内部html跨越多行时不起作用。兔子洞开始了。请建议在解析html时不要使用正则表达式。另外,据我统计,
preg\u replace\u callback()
最多有5个参数。(
$pattern、$callback、$subject、$limit和$count
PREG\u SET\u ORDER
是不必要的,也不会被尊重。我也不认为声明count变量对这种情况有价值。@mickmackusa我的代码片段不是为了这个问题,抱歉。那是为了我的工作。@mickmackusa这是文档错误。php src说它有6个参数。很酷。谢谢你让我知道。尽管如此最后两个参数实际上并不需要。
$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];
    }
}
<?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);
}
pattern('<p>')->match($yourHtml)->only(20);
<?php

$matches = [];

preg_replace_callback(
    '~<p(?:\s.*?)?>(?:.*?)</p>~s',
    function (array $match) use (&$matches) {
        $matches[] = $match[0];
    },
    $html,
    20,
    $_
);

var_dump($matches);
$html = <<<HTML
<div>
    <p class="classy">1
</p>
    <p>2</p>
    <p data-p="<p>notatag</p>">3</p>
    <span data-monkeywrench='<p'>z</span>
    <p
 data-p="<p>notatag</p>">4</p>
    <p>5</p>
</div>
HTML;

$dom = new DOMDocument();
$dom->loadHTML($html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
$xpath = new DOMXPath($dom);
foreach ($xpath->query('//p[position() <= 4]') as $p) {
    echo var_export($p->nodeValue, true) , "\n---\n";
}
'1
'
---
'2'
---
'3'
---
'4'
---