Страницы

Поиск по вопросам

пятница, 14 февраля 2020 г.

Выборка содержимого тэга с помощью регулярных выражений

#html #cpp #регулярные_выражения #парсер


К примеру, у нас есть следующий html-код:


    
        Hello!
    
    
        
Block Content

Text

Content Как можно с помощью регулярных выражений получить содержание оперделенного тэга, указав его имя в этом выражении. Имена тэгов в файле зарание известны и могут передваться в качестве строки или параметра функции, которая и будет осуществлять выборку. К примеру, если я хочу получить содержимое тэга html, то результат выполнения регулярки должен быть следующим: Hello!
Block Content

Text

Content Для тэга body результат должен быть таким:
Block Content

Text

Content и тд. Я попробовал решить эту задачу, написав следующее регулярное выражение: ([\w\s]*)<\/html> Однако, я не получил необходимый результат. Далее, попробовал еще один способ: <.+>\s*(.+)\s*<\/.+> В целом, результат получился почти необходимым, однако, если делать выборку содержимого тэга html, то результат будет таким: Hello!
Block Content

Text

Content т.е. нет начального тэга . EDIT Реализация второго способа выглядит вот так: std::regex m_RegexValue("<.+>\\s*(.+)\\s*<\\/.+>") std::vector result {}; try { std::sregex_iterator next(userData.begin(), userData.end(), m_RegexValue); std::sregex_iterator end; while (next != end) { result.push_back(std::smatch(*next).str()); ++next; } } catch (const std::regex_error& e) { std::cout << e.what() << std::endl; } Как можно это исправить и получить желаемый результат, т.е. чтобы по имени тэга получить все его содержимое? UPDATE После того, как принял советы, которые мне здесь подсказали, возникла потребность выбрать не всё содержимое родительского тега, а лишь чистый текст/контент, без остальных дочерних тегов. Т.е. к примеру, есть следующее содержимое html-страницы: Hello! Some content/data/text
Block Content

Text

Content Как можно выбрать только Some content/data/text? Данная проблема возникла потому, что в некоторых случаях нужно выбирать абсолютно все содержимое родительского тега, а в других - только чистый текст/контент родительского тега.


Ответы

Ответ 1



Правильно в таких случаях использовать специальные парсеры DOM. Я приведу пример регулярного выражения, который может не всегда сработать, например: если в атрибутах есть < или > если требуется найти соответсвтующий закрывающий тег для открывающего (т.е. без поддержки вложенных тегов. Держа вышесказанное в уме, посмотрите на m_RegexValue("<([a-zA-Z_][\\w.-]*)[^>]*>\\s*([\\w\\W]*?)\\s*") Шаблон ([a-zA-Z_][\w.-]*)[^>]*>\s*([\w\W]*?)\s* находит: ([a-zA-Z_][\w.-]*) - Захватывающая подмаска №1 (техническая, нужна для того, чтобы потом использовать обратную ссылку на значение, захваченное этой группой): ASCII-буква или _, за которой может следовать 0 и более букв, цифр, _, . и - [^>]* - 0 и более символов, отличных от > >\s* - > и 0 и более пробельных символов ([\w\W]*?) - Захватывающая подмаска №2: 0 и более любых символов, как можно меньше \s* - 0 и более пробельных символов, а затем . Для нахожения определённых тегов, можно указывать их внутри первых скобок, а после добавлять границу слова. Пример для body: <(body)\b[^>]*>\s*([\w\W]*?)\s* ^^^^ ^^ См. онлайн-демо этого выражения. Однако использовать эту регулярку не рекомендуется, используйте соответствующий парсер. Сссылки на разные HTML-парсеры для С++ можно найти в этом ответе на английском SO.

Ответ 2



Решение задачи можно получить проще если использовать SAX/DOM XML-парсеры. Например, в Qt есть замечательный метод QDomElement::elementsByTagName(...), который возвращает список всех дочерних элементов с указанным именем, а QDomElement::toString() возвращает содержимое элемента в качестве строки. Это все что нужно для того, что бы решить Вашу задачу. Конечно, никто не заставляет использовать Qt, и Вы можете применить здесь любой другой XML-парсер.

Ответ 3



Для подобного разложения используются лексеры и парсеры. Пример сочетания - flex+bison. Хорошая статья , описывающая работу лексера и парсера вместе. P. S. В лексере, для улавливания морфем используются регулярные выражения.

Комментариев нет:

Отправить комментарий