Регулярное выражение для извлечения содержимого тела HTML

Я ищу выражение регулярного выражения, которое позволит мне извлекать HTML-содержимое между тегами body из документа XHTML.

XHTML, который мне нужно проанализировать, будет очень простыми файлами, например, мне не нужно беспокоиться о содержимом JavaScript или тегах <![CDATA[.

Ниже представлена ​​ожидаемая структура HTML-файла, которую я должен проанализировать. Поскольку я точно знаю все содержимое файлов HTML, с которыми мне придется работать, этот фрагмент HTML в значительной степени охватывает весь мой вариант использования. Если мне удастся получить регулярное выражение для извлечения тела этого примера, я буду счастлив.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns = "http://www.w3.org/1999/xhtml">
  <head>
    <title>
    </title>
  </head>
  <body contenteditable = "true">
    <p>
      Example paragraph content
    </p>
    <p>
      &nbsp;
    </p>
    <p>
      <br />
      &nbsp;
    </p>
    <h1>Header 1</h1>
  </body>
</html>

Концептуально я пытался создать строку регулярного выражения, которая соответствовала бы всему, НО внутреннему содержимому тела. При этом я бы использовал метод C# Regex.Split() для получения содержимого тела. Я думал это регулярное выражение:

((.|\n)*<body (.)*>)|((</body>(*|\n)*)

... сработает, но, похоже, он вообще не работает с моим тестовым контентом в RegexBuddy.

Split() - неподходящий инструмент для этой работы. Просто используйте Regex.Match(subject, "(?s)<body[^>]*>(.*)</body>").Groups[1].Value.
Alan Moore 14.09.2016 08:47
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
22
1
50 085
6
Перейти к ответу Данный вопрос помечен как решенный

Ответы 6

XHTML будет легче анализировать с помощью синтаксического анализатора XML, чем с помощью регулярного выражения. Я знаю, что это не то, о чем вы просите, но синтаксический анализатор XML сможет быстро перейти к узлу тела и вернуть вам его содержимое без каких-либо проблем с отображением тегов, которые дает вам регулярное выражение.

Обновлено: В ответ на комментарий здесь; что синтаксический анализатор XML работает слишком медленно.

Существует два типа анализаторов XML: один называется DOM - большой, тяжелый, простой и дружелюбный, он строит дерево из документа, прежде чем вы сможете что-либо сделать. Другой называется SAX, он быстрый, легкий и требует больше работы, он читает файл последовательно. Вам нужно, чтобы SAX нашел тег Body.

Метод DOM хорош для многократного использования, извлечения тегов и определения дочерних элементов. Синтаксический анализатор SAX читает файл по порядку и быстро получает нужную информацию. Regex не будет быстрее, чем парсер SAX, потому что они оба просто проходят по файлу и соответствуют шаблону, за исключением того, что регулярное выражение не прекращает поиск после того, как оно нашло тег тела, потому что регулярное выражение не имеет встроенного знание XML. Фактически, ваш синтаксический анализатор SAX, вероятно, использует небольшие фрагменты регулярного выражения для поиска каждого тега.

Нет причин заново изобретать колесо. Если это XHTML, то это XML, а анализатор XML - это инструмент для работы. +1

Adam Jaskiewicz 10.12.2008 18:09

Это было первое решение, которое мне надоело, но оно работало довольно медленно. Я подумал, что RegEx будет быстрее.

Matthew Ruston 10.12.2008 18:13

Существует два типа анализаторов XML: один называется DOM - большой, тяжелый, простой и дружелюбный, он строит дерево из документа, прежде чем вы сможете что-либо сделать. Другой называется SAX, он быстрый, легкий и требует больше работы, он читает файл последовательно. Вам нужно, чтобы SAX нашел тег Body.

Karl 10.12.2008 18:19

это чрезвычайно простая работа для парсера, она действительно не должна быть медленной

annakata 10.12.2008 18:21

Первоначально я пробовал это с помощью класса .NET System.Xml.XmlDocument, если это объясняет какую-либо медлительность. - Мэтью Растон

Matthew Ruston 10.12.2008 18:30

Даже если он работает медленнее, он будет обрабатывать все исключительные случаи, такие как name = "</body>" и т. д.

bezmax 12.12.2008 10:36
Ответ принят как подходящий

Это сработает?

((?:.(?!<body[^>]*>))+.<body[^>]*>)|(</body\>.+)

Конечно, вам нужно добавить необходимый \s, чтобы учесть < body ...> (элемент с пробелами), как в:

((?:.(?!<\s*body[^>]*>))+.<\s*body[^>]*>)|(<\s*/\s*body\s*\>.+)

Если подумать, я не уверен, зачем мне нужен негативный прогноз ... Это тоже должно сработать (для правильно сформированного документа xhtml):

(.*<\s*body[^>]*>)|(<\s*/\s*body\s*\>.+)

Ммм, похоже, хороший случай продемонстрировать, что RE не следует использовать против (неизвестного) HTML: <body onload = "DoSomething ('>');"> действительно ... :-)

PhiLho 10.12.2008 19:10

PhiLho, вы ошибаетесь, это недопустимый XHTML. ">" должно быть экранировано как "& gt;" быть XML-правильно сформированным. Однако веб-браузеры используют различные уловки для чтения неработающего HTML / XHTML. Страницы с содержимым JavaScript обычно не имеют правильного формата XML, если они не помещены в CDATA.

Hendy Irawan 01.01.2011 02:37

Спасибо за это. Не могли бы вы подробнее описать, как использовать это с библиотекой Regex на C#. оператор для возврата желаемого содержимого из строки HTML-документа

end user 23.10.2020 15:47

@enduser двенадцать лет спустя, я считаю, что этот ответ больше касался использования регулярного выражения, чем его использования в C#. Для последнего я бы следовал одному из примеров из c-sharpcorner.com/article/c-sharp-regex-examples.

VonC 23.10.2020 15:49
/<body[^>]*>(.*)</body>/s

заменить

\1

Это должно соответствовать всему документу и помещать тело в \ 3. Таким образом, вы знаете, что если он не соответствует всему документу, что при форматировании текущего документа нужно еще кое-что учесть, и вы можете выдать ошибку.

Kev 10.12.2008 18:09

Я знаю, что это очень старый пост, но черт возьми ... Мне нравится этот ответ, и я должен был сообщить об этом.

stefgosselin 04.11.2011 05:45

Обратите внимание, что в регулярных выражениях Perl и Java необходимо включить флаг s, чтобы внутренний (.*) соответствовал символам новой строки, что обычно и требуется. Также, на мой взгляд, необязательно иметь начальную или конечную группировку - более простым ответом будет /<body[^>]*>(.*)</body>/s и использование группы 1.

aarestad 25.08.2016 17:36

@aarestad спасибо, я редактировал, вы правы - мои навыки работы с регулярными выражениями на тот момент были немного зеленее :)

Kev 26.08.2016 11:58

Почему ты не можешь просто разделить это на

</{0,1}body[^>]*> 

а взять вторую струну? Я считаю, что это будет намного быстрее, чем искать огромное регулярное выражение.

Тем не менее, если вы исправите это, ваш подход может быть проще. :)

Kev 10.12.2008 18:08

Что ж, я только что заметил это, прежде чем вы разместили комментарий и отредактировали этот ответ: P

bezmax 10.12.2008 18:09

На самом деле у меня недостаточно очков для редактирования ... должно быть, это был кто-то другой.

Kev 10.12.2008 18:54
String toMatch = "aaaaaaaaaaabcxx sldjfkvnlkfd <body>i m avinash</body>";
Pattern pattern=Pattern.compile(".*?<body.*?>(.*?)</body>.*?");
Matcher matcher=pattern.matcher(toMatch);
if (matcher.matches()) {
    System.out.println(matcher.group(1));
}

Соответствует первому тегу тела: <\s*body.*?>

Соответствует последнему тегу тела: <\s*/\s*body.*?>

(примечание: мы учитываем пробелы в середине тегов, что, кстати, является полностью допустимой разметкой)

Объедините их вместе вот так, и вы получите все, что между ними, включая теги тела: <\s*body.*?>.*?<\s*/\s*body.*?>. И убедитесь, что вы используете режим Singleline, который игнорирует разрывы строк.

Это работает в VB.NET и, надеюсь, в других тоже!

Другие вопросы по теме