const regex = /(?(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)*+\>)) #Закрытие списка закрывает последний элемент
)/gui;
// Alternative syntax using RegExp constructor
// const regex = new RegExp('(?(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)*+\\>)) #Закрытие списка закрывает последний элемент
)', 'gui')
const 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>`;
// Reset `lastIndex` if this regex is defined globally
// regex.lastIndex = 0;
let m;
while ((m = regex.exec(str)) !== null) {
// This is necessary to avoid infinite loops with zero-width matches
if (m.index === regex.lastIndex) {
regex.lastIndex++;
}
// The result can be accessed through the `m`-variable.
m.forEach((match, groupIndex) => {
console.log(`Found match, group ${groupIndex}: ${match}`);
});
}
Please keep in mind that these code samples are automatically generated and are not guaranteed to work. If you find any syntax errors, feel free to submit a bug report. For a full regex reference for JavaScript, please visit: https://developer.mozilla.org/en/docs/Web/JavaScript/Guide/Regular_Expressions