Предполагая, что все элементы имеют конечные теги, и никто не стал умным, добавив пробелы внутри начальных или конечных тегов, и что некоторые элементы предшествуют элементам списка, все, что вам нужно сделать, это примерно так (в синтаксисе Perl, вероятно, совместимо с PCRE библиотека, минус оператор m//
):
m/(?<!li)>[^<]*<li/i
для идентификации первого списка в группе. В разобранном виде (с флагом x
, для удобства чтения):
m/
(?<!li)> # the end of a start or end tag that isn't part of an li element
[^<]* # some non-angle-bracket characters -- in-between tag content
<li # the beginning of an li element
/xi # space insensitive, case insensitive (respectively)
И тогда вы могли бы пройти через следующий блок с большей уверенностью, что между элементами списка, скорее всего, ничего не будет, пока вы не прочитаете его конец, не сохраните эту позицию и не воспользуетесь этим шаблоном снова.
Выяснить, где это заканчивается, сложнее без парсера. Вы можете использовать что-то вроде (это сокращенно)
m/(?<=<li).*?<(div|form|p)/i
, где вы перечисляете все не встроенные элементы, что приведет к закрытию li и ul и завершению всего списка. Но другой способ закрытия списка - простота - закрытие контейнера.
Если сами элементы элемента списка правильно сформированы (имеют закрывающие теги), то этого может быть достаточно для размещения закрывающего тега списков:
m{</li>.*?<(?!li)}i