Использование регулярных выражений C # для удаления тегов HTML

139

Как использовать регулярное выражение C # для замены / удаления всех тегов HTML, включая угловые скобки? Может кто-нибудь помочь мне с кодом?

Keltex
источник
2
------- stackoverflow.com/a/1732454/961234
Рафаэль
Вы не указываете это, но я предполагаю, что вы также хотите полностью удалить элементы скрипта и стиля, а не просто удалить тег. Приведенный ниже ответ HTML Agility Pack подходит для удаления тегов, но для удаления скрипта и стиля вам также понадобится что-то вроде stackoverflow.com/questions/13441470/…
Джон
1
В вопросе, обозначенном как дубликат, содержится много информации (и Тони Пони!), Но он запрашивал только открывающие теги, а не все теги. Так что я не уверен, что технически это дубликат. Тем не менее, ответ тот же: не надо.
goodeye

Ответы:

155

Как часто говорилось ранее, вы не должны использовать регулярные выражения для обработки документов XML или HTML. Они не очень хорошо работают с документами HTML и XML, потому что нет способа выразить вложенные структуры в общем виде.

Вы можете использовать следующее.

String result = Regex.Replace(htmlDocument, @"<[^>]*>", String.Empty);

Это будет работать в большинстве случаев, но будут случаи (например, CDATA, содержащий угловые скобки), когда это не будет работать должным образом.

Даниэль Брюкнер
источник
13
Это наивная реализация .. То есть <div id = "x <4>">, к сожалению, является допустимым HTML. Хотя справляется с большинством нормальных случаев ..
Райан Эмерл
8
Как уже говорилось, я знаю, что это выражение в некоторых случаях не работает. Я даже не уверен, можно ли без ошибок обработать общий случай любым регулярным выражением.
Даниэль Брюкнер,
1
Нет, это не поможет во всех случаях! его жадный.
Джейк,
13
@Cipher, почему, по-твоему, жадность - это проблема? Если предположить, что совпадение начинается с начала действительного тега HTML, оно никогда не будет выходить за пределы этого тега. Для этого нужен [^>].
Алан Мур,
1
@AlanMoore html не является "обычным языком", т.е. вы не можете правильно сопоставить все, что является допустимым html, с регулярными выражениями. см .: stackoverflow.com/questions/590747/…
Kache
78

Правильный ответ - не делайте этого, используйте HTML Agility Pack .

Отредактировано для добавления:

Чтобы бессовестно украсть комментарий Джесси ниже и избежать обвинений в неадекватном ответе на вопрос по прошествии всего этого времени, вот простой и надежный фрагмент с использованием пакета HTML Agility Pack, который работает даже с самыми несовершенно сформированными, капризными фрагментами HTML:

HtmlDocument doc = new HtmlDocument();
doc.LoadHtml(Properties.Resources.HtmlContents);
var text = doc.DocumentNode.SelectNodes("//body//text()").Select(node => node.InnerText);
StringBuilder output = new StringBuilder();
foreach (string line in text)
{
   output.AppendLine(line);
}
string textOnly = HttpUtility.HtmlDecode(output.ToString());

Существует очень мало оправданных случаев использования регулярного выражения для синтаксического анализа HTML, поскольку HTML не может быть правильно проанализирован без учета контекста, что очень сложно обеспечить даже в нетрадиционном механизме регулярных выражений. Вы можете частично добиться этого с помощью RegEx, но вам нужно будет выполнить ручную проверку.

Html Agility Pack может предоставить вам надежное решение, которое уменьшит необходимость вручную исправлять отклонения, которые могут возникнуть в результате наивного отношения к HTML как к контекстно-свободной грамматике.

Регулярное выражение может дать вам в основном то, что вы хотите большую часть времени, но в очень распространенных случаях оно не работает. Если вы можете найти лучший / более быстрый парсер, чем HTML Agility Pack, сделайте это, но, пожалуйста, не подвергайте мир еще большему взлому HTML.

JasonTrue
источник
27
HTML Agility Pack - это не ответ на все вопросы, связанные с работой с HTML (например, что, если вы хотите работать только с фрагментами HTML-кода ?!).
PropellerHead,
7
Он неплохо работает с фрагментами HTML, и это лучший вариант для сценария, описанного исходным плакатом. С другой стороны, Regex работает только с идеализированным HTML и не работает с совершенно правильным HTML, потому что грамматика HTML не является регулярной. Если бы он использовал Ruby, я бы все равно предложил nokogiri, hpricot или beautifulsoup для Python. Лучше всего относиться к HTML как к HTML, а не к произвольному текстовому потоку без грамматики.
JasonTrue
1
HTML не является регулярной грамматикой и поэтому не может быть проанализирован только с помощью регулярных выражений. Вы можете использовать регулярные выражения для лексирования, но не для синтаксического анализа. Это действительно так просто. Лингвисты согласились бы с этим еще до того, как появился HTML.
JasonTrue
20
Это не вопрос мнения. Регулярное выражение может дать вам в основном то, что вы хотите большую часть времени, но в очень распространенных случаях оно не работает. Если вы можете найти лучший / более быстрый парсер, чем HTML Agility Pack, сделайте это, но, пожалуйста, не подвергайте мир еще большему взлому HTML.
JasonTrue
2
Вы не сможете правильно идентифицировать HTML-теги, не проанализировав HTML. Вы понимаете всю грамматику HTML? Посмотрите на злой хак, чтобы подобраться «довольно близко», что предлагают другие ответы, и скажите мне, почему вы хотите поддерживать это. Если вы откажетесь от моего голоса, потому что для вашего образца ввода работает хакерская быстрая попытка, это не сделает ваше решение правильным. Я иногда использовал регулярные выражения для создания отчетов из содержимого HTML или для исправления некоторых ссылок CSS с использованием отрицательного соответствия в & gt; чтобы ограничить вероятность ошибок, но мы сделали дополнительные проверки; это не было универсальной целью.
JasonTrue
38

Вопрос слишком широкий, чтобы на него можно было дать однозначный ответ. Вы говорите об удалении всех тегов из реального HTML-документа, например веб-страницы? Если это так, вам необходимо:

  • удалите объявление <! DOCTYPE или пролог <? xml, если они существуют
  • удалить все комментарии SGML
  • удалить весь элемент HEAD
  • удалить все элементы SCRIPT и STYLE
  • делать Грабтар-знает-что с элементами FORM и TABLE
  • удалите оставшиеся теги
  • удалите последовательности <! [CDATA [и]]> из разделов CDATA, но оставьте их содержимое в покое

Это просто не в моей голове - я уверен, что это еще не все. После того, как вы все это сделаете, в некоторых местах вы получите слова, предложения и абзацы, соединенные вместе, а в других - большие куски бесполезного пробела.

Но, если вы работаете только с фрагментом и можете просто удалить все теги, вот регулярное выражение, которое я бы использовал:

@"(?></?\w+)(?>(?:[^>'""]+|'[^']*'|""[^""]*"")*)>"

Сопоставление строк в одинарных и двойных кавычках в их собственных альтернативах достаточно для решения проблемы угловых скобок в значениях атрибутов. Я не вижу необходимости явно сопоставлять имена атрибутов и другие вещи внутри тега, как это делает регулярное выражение в ответе Райана; первая альтернатива обрабатывает все это.

Если вас интересуют эти (?>...)конструкции, они атомные группы . Они делают регулярное выражение немного более эффективным, но, что более важно, предотвращают неконтролируемый откат назад, на что всегда следует обращать внимание, когда вы смешиваете чередование и вложенные квантификаторы, как это сделал я. Я действительно не думаю, что это будет проблемой здесь, но я знаю, что если я не упомяну об этом, это сделает кто-то другой. ;-)

Это регулярное выражение, конечно, не идеально, но оно, вероятно, настолько хорошо, насколько вам когда-либо понадобится.

Алан Мур
источник
1
Это, безусловно, лучший ответ. Вы отвечаете на вопрос автора и объясняете, почему не следует использовать регулярное выражение для данной задачи. Отлично сработано.
JWilliams
26
Regex regex = new Regex(@"</?\w+((\s+\w+(\s*=\s*(?:"".*?""|'.*?'|[^'"">\s]+))?)+\s*|\s*)/?>", RegexOptions.Singleline);

Источник

Райан Эмерл
источник
18

@JasonTrue правильно, что удаление тегов HTML не должно выполняться с помощью регулярных выражений.

Убрать HTML-теги с помощью HtmlAgilityPack довольно просто:

public string StripTags(string input) {
    var doc = new HtmlDocument();
    doc.LoadHtml(input ?? "");
    return doc.DocumentNode.InnerText;
}
zzzzBov
источник
1
Хотя я немного опоздал с этим, я хотел бы упомянуть, что это также работает с xml, например, созданным Word и другими офисными продуктами. любой, у кого когда-либо была необходимость иметь дело с Word xml, неплохо было бы взглянуть на его использование, потому что он действительно очень помогает, особенно если вам нужно удалить теги из содержимого, а это именно то, для чего мне это нужно.
Стив Петтифер
Когда все остальное казалось безуспешным, этот простой фрагмент кода спас положение. Благодарность!
Тед Крапф,
14

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

Мне нужно было сделать это с помощью некоторого Html, который был создан текстовым редактором, всегда весело и с играми.

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

В моем случае в этот микс были добавлены и теги. Кто-то может счесть мою (очень немного) менее наивную реализацию полезной отправной точкой.

   /// <summary>
    /// Removes all html tags from string and leaves only plain text
    /// Removes content of <xml></xml> and <style></style> tags as aim to get text content not markup /meta data.
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    public static string HtmlStrip(this string input)
    {
        input = Regex.Replace(input, "<style>(.|\n)*?</style>",string.Empty);
        input = Regex.Replace(input, @"<xml>(.|\n)*?</xml>", string.Empty); // remove all <xml></xml> tags and anything inbetween.  
        return Regex.Replace(input, @"<(.|\n)*?>", string.Empty); // remove any tags but not there content "<p>bob<span> johnson</span></p>" becomes "bob johnson"
    }
CountZero
источник
1
Помимо очевидных кроссплатформенных проблем с переносом строк, неуклюжий квантификатор работает медленно, когда контент разделен. Используйте вещи , как <xml>.*(?!</xml>)</xml>с RegexOptions.SingleLineмодификатором для первых двух и <[^>]*>для последнего. Первые также могут быть объединены путем захваченного чередования имени первого тега и обратных ссылок на него в отрицательном прогнозе и конечном теге.
ChrisF
5

попробуйте метод регулярного выражения по этому URL-адресу: http://www.dotnetperls.com/remove-html-tags

/// <summary>
/// Remove HTML from string with Regex.
/// </summary>
public static string StripTagsRegex(string source)
{
return Regex.Replace(source, "<.*?>", string.Empty);
}

/// <summary>
/// Compiled regular expression for performance.
/// </summary>
static Regex _htmlRegex = new Regex("<.*?>", RegexOptions.Compiled);

/// <summary>
/// Remove HTML from string with compiled Regex.
/// </summary>
public static string StripTagsRegexCompiled(string source)
{
return _htmlRegex.Replace(source, string.Empty);
}
Овидат
источник
3

использовать это..

@"(?></?\w+)(?>(?:[^>'""]+|'[^']*'|""[^""]*"")*)>"
Swaroop
источник
-1

Используйте этот метод для удаления тегов:

public string From_To(string text, string from, string to)
{
    if (text == null)
        return null;
    string pattern = @"" + from + ".*?" + to;
    Regex rx = new Regex(pattern, RegexOptions.Compiled | RegexOptions.IgnoreCase);
    MatchCollection matches = rx.Matches(text);
    return matches.Count <= 0 ? text : matches.Cast<Match>().Where(match => !string.IsNullOrEmpty(match.Value)).Aggregate(text, (current, match) => current.Replace(match.Value, ""));
}
АнисНурАли
источник