Регулярное выражение для извлечения содержимого тела 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.

10.12.2008 14:53:56
Split()это неправильный инструмент для этой работы. Просто используйте Regex.Match(subject, "(?s)<body[^>]*>(.*)</body>").Groups[1].Value.
Alan Moore 14.09.2016 05:47:10
6 ОТВЕТОВ
РЕШЕНИЕ

Будет ли это работать?

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

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

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

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

(.*<\s*body[^>]*>)|(<\s*/\s*body\s*\>.+)
23
11.12.2008 06:25:26
Ммм, похоже, хороший пример для демонстрации того, что RE не должны использоваться против (неизвестного) HTML: <body onload = "DoSomething ('>');"> действителен ... :-)
PhiLho 10.12.2008 16:10:56
PhiLho, вы не правы, это не правильный XHTML. ">" должен быть экранирован как "& gt;" быть XML-хорошо сформированным. Тем не менее, веб-браузеры используют различные методы для чтения испорченного HTML / XHTML. Страницы с содержимым JavaScript обычно не имеют правильной формы XML, если они не помещены в CDATA.
Hendy Irawan 31.12.2010 23:37:52

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

РЕДАКТИРОВАТЬ: В ответ на комментарий здесь; что анализатор XML слишком медленный.

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

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

9
10.12.2008 15:22:35
Нет причин заново изобретать колесо. Если это XHTML, то это XML, а синтаксический анализатор XML - это инструмент для работы. +1
Adam Jaskiewicz 10.12.2008 15:09:59
Это было первое решение, которое я устал, но, похоже, оно работало довольно медленно. Я полагал, что RegEx будет быстрее.
Matthew Ruston 10.12.2008 15:13:18
Существует два вида синтаксического анализатора XML, один из которых называется DOM, он большой, тяжелый, простой и удобный, он строит дерево документа, прежде чем что-либо делать. Другой называется SAX, он быстрый и легкий и требует больше работы, он читает файл последовательно. Вы хотите, чтобы SAX нашел тег Body.
Karl 10.12.2008 15:19:48
это очень простая работа для парсера, она действительно не должна быть медленной
annakata 10.12.2008 15:21:22
Первоначально я пытался сделать это с классом .NET System.Xml.XmlDocument, если это объясняет какую-либо медлительность. - Мэтью Растон
Matthew Ruston 10.12.2008 15:30:47
/<body[^>]*>(.*)</body>/s

заменить

\1
3
26.08.2016 08:57:13
Это должно соответствовать всему документу и поместить тело в \ 3. Таким образом, вы знаете, если он не соответствует всему документу, что форматирование текущего документа имеет что-то еще, чтобы рассмотреть, и вы можете выдать ошибку.
Kev 10.12.2008 15:09:55
Я знаю, что это очень старый пост, но черт ... Мне нравится этот ответ, и я должен был дать ему знать.
stefgosselin 4.11.2011 01:45:56
Обратите внимание, что в регулярных выражениях Perl и Java вы должны включить sфлаг, чтобы внутреннее (.*)сопоставление совпадало с символами новой строки, что обычно является тем, что вам нужно. На мой взгляд, также нет необходимости иметь /<body[^>]*>(.*)</body>/s
aarestad 25.08.2016 14:36:40
@aarestad спасибо, я отредактировал, ты прав - мои навыки регулярных выражений были немного более экологичными на тот момент :)
Kev 26.08.2016 08:58:30

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

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

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

3
10.12.2008 15:07:27
Тем не менее, если вы исправите это, ваш подход может быть проще. :)
Kev 10.12.2008 15:08:55
Ну, я только что заметил это, прежде чем вы опубликовали комментарий и отредактировали этот ответ: P
bezmax 10.12.2008 15:09:39
На самом деле у меня недостаточно очков для редактирования ... Должно быть, это был кто-то другой.
Kev 10.12.2008 15:54:10
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));
}
5
11.07.2011 19:14:46
Отлично! Спасибо за это!
Jef 7.01.2013 12:04:23

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

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

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

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

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

1
14.09.2016 23:21:49