N
N
Name2021-06-25 10:12:00
PHP
Name, 2021-06-25 10:12:00

How to specify block boundaries for preg_match_all?

We take in an array all li:

$q = '
<p>какой-то текст</p>
<ul class="ul">
<li>aaa</li>
<li>bbb</li>
<li>ccc</li>
</ul>
<p>какой-то текст</p>
<h2>aaa</h2>
<p>какой-то текст</p>
<h3>ccc</h3>
<p>какой-то текст</p>
<h3>bbb</h3>
<p>какой-то текст</p>
';
preg_match_all("!<li>.*?</li>!", $q, $matches);
      print_r ($matches[0]);


if you add another ul list, then it will also be included in the array.

How to put only li from the class="ul" block into an array?

Answer the question

In order to leave comments, you need to log in

1 answer(s)
K
KraydenSharp, 2021-06-26
@KraydenSharp

Parsing HTML with regular expressions is quite difficult.
Here is the regex example you need https://regex101.com/r/Yxki2K/1/ .
It turned out quite a lot of things, but, in which case, by changing the first 3 groups in DEFINE, you can easily look for other tags.
In order to understand everything that is written there, I left comments.
If someone still uses this, then keep in mind that this regular expression does not take into account nested elements that match the selector and in some places not valid HTML.ul.ul, ul[class="ul"]

$re = '/(?(DEFINE) #Это блок с объявлением функций

    #Этот блок - единственное место, где нужно подставлять значения
    (?<tagName>ul) #Имя тега
    (?<attrName>class) #Атрибут тега
    (?<attrValue>ul) #Значение тега

    (?<anyAttrName>[^\s\>\=]*+) #Любое название атрибута
    (?<anyAttrValue>\"[^\"]*+\"|\'[^\']*+\'|\`[^\']*+\`|[^\s\>]*+) #Любое значение атрибута
    (?<anyAttr>(?&anyAttrName)\s*+(?:\=\s*+(?&anyAttrValue)\s*+)?+) #Любой атрибут

    #Если нужно найти точное вхождение значения атрибута
    (?<attr>
        (?&attrName)\b\s*+\=\s*+ #Нужное нам название атрибута
        (?: #Поиск точного вхождения
            \"(?&attrValue)\"|
            \'(?&attrValue)\'|
            \`(?&attrValue)\`|
            (?&attrValue)(?=[\s\>])
        )
    )

    #Если нужно искать в атрибуте значение как в классах
    (?<attrClass>
        (?&attrName)\b\s*+\=\s*+ #Нужное нам название атрибута
        (?: #Поиск значения как в классах
            \"[^\"]*?\b(?&attrValue)\b[^\"]*+\"|
            \'[^\']*?\b(?&attrValue)\b[^\']*+\'|
            \`[^\`]*?\b(?&attrValue)\b[^\`]*+\`|
            (?&attrValue)(?=[\s\>])
        )
    )

    #В зависимости от того, какую из 2 функций выше мы хотим использовать для проверки атрибута
    #Строгое сравнение значения
    (?<tag>\<(?&tagName)\b\s*+(?&anyAttr)*?(?&attr)(?&anyAttr)*?\>) #Использовать так: (?&tag)
    #Поиск значения как в классах
    (?<tagClass>\<(?&tagName)\b\s*+(?&anyAttr)*?(?&attrClass)(?&anyAttr)*?\>) #Использовать так: (?&tagClass)

) #Этот огровный блок с функциями закончился

(?:[^\<]++(*SKIP)|\G|\C*?(?<parentTag>(?&tagClass)))[^\<]*+\K #После того, как нашли тег сбросили состояние нулевой группы
(?<openTag>\<li\b\s*+(?&anyAttr)*+\>) #У тега могут быть атрибуты
(?<innerHTML>\C*?) #Внутреннее содержимое тега
(?<closeTag>
    \<\/li\b\s*+(?&anyAttr)*+>| #В HTML у закрывающих тегов нет атрибутов, но HTML от этого не ломается
    (?=(?&openTag))| #Теги элементов списка необязательно закрывать согласно документации
    (?=(?<closeParentTag>\<\/ul\b\s*+(?&anyAttr)*+\>)) #Закрытие списка закрывает последний элемент
)/xuJi';
$str = '<ul>
    <li class="li anyClass">aaa</li>
    <li>bbb
    <li>ccc
</ul>
<p>какой-то текст</p>
<ul data-class="ul anyClass" class="ul anyClass" data-id=`ul` id=\'ul\' data-data=ul data-empty>
    <li class="li anyClass">aaa</li>
    <li >aaa</li>
    <li>bbb
    <li>ccc
</ul>
<p>какой-то текст</p>
<ul>
    <li class="li anyClass">aaa</li>
    <li>bbb
    <li>ccc
</ul>
<p>какой-то текст</p>
<ul data-class="ul anyClass" class="ul anyClass" data-id=`ul` id=\'ul\' data-data=ul data-empty>
    <li class="li anyClass">aaa</li>
    <li>bbb
    <li>ccc
</ul>
<p>какой-то текст</p>
<ul>
    <li class="li anyClass">aaa</li>
    <li>bbb
    <li>ccc
</ul>';

preg_match_all($re, $str, $matches, PREG_SET_ORDER, 0);

// Print the entire match result
var_dump($matches);

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question