# coding=utf8
# the above tag defines encoding for this document and is for Python 2.x compatibility
import re
regex = r"""
(?(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)*+\>)) #Закрытие списка закрывает последний элемент
)
"""
test_str = ("<ul>\n"
" <li class=\"li anyClass\">aaa</li>\n"
" <li>bbb\n"
" <li>ccc\n"
"</ul>\n"
"<p>какой-то текст</p>\n"
"<ul data-class=\"ul anyClass\" class=\"ul anyClass\" data-id=`ul` id='ul' data-data=ul data-empty>\n"
" <li class=\"li anyClass\">aaa</li>\n"
" <li >aaa</li>\n"
" <li>bbb\n"
" <li>ccc\n"
"</ul>\n"
"<p>какой-то текст</p>\n"
"<ul>\n"
" <li class=\"li anyClass\">aaa</li>\n"
" <li>bbb\n"
" <li>ccc\n"
"</ul>\n"
"<p>какой-то текст</p>\n"
"<ul data-class=\"ul anyClass\" class=\"ul anyClass\" data-id=`ul` id='ul' data-data=ul data-empty>\n"
" <li class=\"li anyClass\">aaa</li>\n"
" <li>bbb\n"
" <li>ccc\n"
"</ul>\n"
"<p>какой-то текст</p>\n"
"<ul>\n"
" <li class=\"li anyClass\">aaa</li>\n"
" <li>bbb\n"
" <li>ccc\n"
"</ul>")
matches = re.finditer(regex, test_str, re.VERBOSE | re.UNICODE | re.IGNORECASE)
for matchNum, match in enumerate(matches, start=1):
print ("Match {matchNum} was found at {start}-{end}: {match}".format(matchNum = matchNum, start = match.start(), end = match.end(), match = match.group()))
for groupNum in range(0, len(match.groups())):
groupNum = groupNum + 1
print ("Group {groupNum} found at {start}-{end}: {group}".format(groupNum = groupNum, start = match.start(groupNum), end = match.end(groupNum), group = match.group(groupNum)))
# Note: for Python 2.7 compatibility, use ur"" to prefix the regex and u"" to prefix the test string and substitution.
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 Python, please visit: https://docs.python.org/3/library/re.html