Регулярное выражение для определенных тегов и их содержимого, сгруппированных по имени тега.
Вопрос
Вот ввод (html, а не xml):
... html content ...
<tag1> content for tag 1 </tag1>
<tag2> content for tag 2 </tag2>
<tag3> content for tag 3 </tag3>
... html content ...
Я хотел бы получить 3 матча, каждый с двумя группами.Первая группа будет содержать имя тега, а вторая группа будет содержать внутренний текст тега.Есть только эти три тега, поэтому он не обязательно должен быть универсальным.
Другими словами:
match.Groups["name"] would be "tag1"
match.Groups["value"] would be "content for tag 2"
Есть идеи?
Решение
Я не понимаю, почему вы хотите использовать для этого имена групп совпадений.
Вот регулярное выражение, которое будет сопоставлять имя и содержимое тега с пронумерованными вложенными совпадениями.
<(tag1|tag2|tag3)>(.*?)</$1>
Вот вариант с именами групп в стиле .NET.
<(?'name'tag1|tag2|tag3)>(?'value'.*?)</\k'name'>.
РЕДАКТИРОВАТЬ
RegEx адаптирован согласно пояснениям автора вопроса.
Другие советы
Regex для этого может быть:
/<([^>]+)>([^<]+)<\/\1>/
Но это в общих чертах, поскольку я мало что знаю о механизме побега .NET.Чтобы перевести это:
- первая группа соответствует имени первого тега между < и >
- вторая группа соответствует содержимому (от > до следующего <
- конечная проверка, закрыт ли первый тег
ХТХ
Спасибо всем, но ни одно из регулярных выражений не работает.:( Возможно я недостаточно конкретно выразился, извините за это.Вот точный HTML-код, который я пытаюсь разобрать:
...some html content <b> etc </b> ...
<user> hello <b>mitch</b> </user>
...some html content <b> etc </b> ...
<message> some html <i>message</i> <a href....>bla</a> </message>
...some html content <b> etc </b> ...
Надеюсь, теперь стало яснее.Мне нужны теги USER и MESSAGE.
Мне нужно получить два совпадения, каждое с двумя группами.Первая группа должна была дать мне имя тега (пользователя или сообщение), а вторая группа предоставить мне весь внутренний текст тега.
Являются ли данные правильным XML-файлом или они просто так выглядят?
Если это html, то Пакет гибкости HTML заслуживает изучения — это предоставляет DOM (похожий на XmlDocument), который вы можете использовать для запроса данных:
string input = @"<html>...some html content <b> etc </b> ...
<user> hello <b>mitch</b> </user>
...some html content <b> etc </b> ...
<message> some html <i>message</i> <a href....>bla</a> </message>
...some html content <b> etc </b> ...</html>";
HtmlDocument doc = new HtmlDocument();
doc.LoadHtml(input);
foreach (HtmlNode node in doc.DocumentNode.SelectNodes("//user | //message"))
{
Console.WriteLine("{0}: {1}", node.Name, node.InnerText);
// or node.InnerHtml to keep the formatting within the content
}
Это выводит:
user: hello mitch
message: some html message bla
Если вам нужны теги форматирования, используйте .InnerHtml вместо .InnerText.
Если это xml, то для кодирования всего спектра xml лучше использовать синтаксический анализатор xml.Для XML-файла малого и среднего размера можно загрузить его в DOM, например XmlDocument, а затем запросить узлы (например, «//*»).Для огромных XML-файлов можно использовать XmlReader.
Если данным не нужно беспокоиться о полном XML-файле, то какое-нибудь простое регулярное выражение не должно быть слишком сложным...упрощенный пример (без атрибутов, без пространств имен, без вложенного XML) может быть таким:
string input = @"blah <tag1> content for tag 1 </tag1> blop
<tag2> content for tag 2 </tag2> bloop
<tag3> content for tag 3 </tag3> blip";
const string pattern = @"<(\w+)>\s*([^<>]*)\s*</(\1)>";
Console.WriteLine(Regex.IsMatch(input, pattern));
foreach(Match match in Regex.Matches(input, pattern)) {
Console.WriteLine("{0}: {1}", match.Groups[1], match.Groups[2]);
}
Проблема заключалась в том, что люди ([^<]*), которые люди использовали для сопоставления вещей внутри тегов, соответствовали открывающему < вложенных тегов, а затем закрывающий тег вложенного тега не соответствовал внешнему тегу, и поэтому регулярное выражение не удалось.
Вот немного более надежная версия регулярного выражения Томалака, позволяющая использовать атрибуты и пробелы:
Regex tagRegex = new Regex(@"<\s*(?<tag>" + string.Join("|", tags) + @")[^>]*>(?<content>.*?)<\s*/\s*\k<tag>\s*>", RegexOptions.IgnoreCase);
Очевидно, что если вам когда-либо понадобится использовать только определенный набор тегов, вы можете заменить
string.Joing("|", tags)
с жестко запрограммированным списком тегов, разделенным трубами.
Ограничения регулярного выражения заключаются в том, что если у вас есть один тег, который вы пытаетесь сопоставить, вложенный внутри другого, он будет соответствовать только внешнему тегу.то есть
<user>abc<message>def</message>ghi</user>
Он будет соответствовать внешнему тегу пользователя, но не внутреннему тегу сообщения.
Он также не обрабатывает кавычки > в атрибутах, например:
<user attrib="oops>">
Это просто будет соответствовать
<user attrib="упс>
как тег и
">
будет частью содержимого тегов.
Это даст вам именованные группы захвата для того, что вы хотите.Однако это не будет работать для вложенных тегов.
/<(?<name>[^>]+)>(?<value>[^<]+)</\1>/