Usando expressões regulares em C # para remover tags HTML

139

Como uso a expressão regular C # para substituir / remover todas as tags HTML, incluindo os colchetes angulares? Alguém por favor pode me ajudar com o código?

Keltex
fonte
Você não indica, mas estou deduzindo que você também deseja remover completamente os elementos de script e estilo e não apenas remover a tag. A resposta da agilidade pacote HTML abaixo é correto para retirar as etiquetas, mas para o script de remoção e estilo, você também vai precisar de algo como stackoverflow.com/questions/13441470/...
John
1
A pergunta indicada como duplicada tem muitas informações (e Tony, o Pônei!), Mas solicitou apenas tags de abertura, nem todas. Portanto, não tenho certeza se é tecnicamente uma duplicata. Dito isto, a resposta é a mesma: não.
Goodeye 17/05

Respostas:

154

Como dito anteriormente, você não deve usar expressões regulares para processar documentos XML ou HTML. Eles não funcionam muito bem com documentos HTML e XML, porque não há como expressar estruturas aninhadas de maneira geral.

Você pode usar o seguinte.

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

Isso funcionará na maioria dos casos, mas haverá casos (por exemplo, CDATA contendo colchetes angulares) em que isso não funcionará conforme o esperado.

Daniel Brückner
fonte
13
Esta é uma implementação ingênua. Ou seja, <div id = "x <4>"> é, infelizmente, um html válido. Lida com casos mais sãs embora ..
Ryan Emerle
8
Como afirmado, estou ciente de que essa expressão falhará em alguns casos. Não tenho certeza se o caso geral pode ser tratado por qualquer expressão regular sem erros.
Daniel Brückner
1
Não, isso irá falhar em todos os casos! é ganancioso.
Jake
13
@ Cipher, por que você acha que a ganância é um problema? Supondo que a correspondência comece no início de uma tag HTML válida, ela nunca se estenderá além do final dessa tag. É para isso que serve [^>].
277 Alan Moore
1
O @AlanMoore html não é um "idioma comum", ou seja, você não pode corresponder corretamente tudo o que é html válido com expressões regulares. Veja: stackoverflow.com/questions/590747/…
Kache 14/03
78

A resposta correta é não fazer isso, use o HTML Agility Pack .

Editado para adicionar:

Para roubar descaradamente o comentário abaixo de jesse e evitar ser acusado de responder inadequadamente à pergunta depois de todo esse tempo, aqui está um trecho simples e confiável usando o HTML Agility Pack que funciona com os bits caprichosos de HTML ainda mais imperfeitos:

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());

Existem muito poucos casos defensáveis ​​para o uso de uma expressão regular para analisar HTML, pois o HTML não pode ser analisado corretamente sem uma conscientização de contexto que é muito dolorosa de fornecer, mesmo em um mecanismo de regex não tradicional. Você pode chegar até lá com um RegEx, mas precisará fazer verificações manuais.

O Html Agility Pack pode fornecer uma solução robusta que reduzirá a necessidade de corrigir manualmente as aberrações que podem resultar do tratamento ingênuo do HTML como uma gramática livre de contexto.

Uma expressão regular pode obter o que você deseja na maioria das vezes, mas falhará em casos muito comuns. Se você puder encontrar um analisador melhor / mais rápido que o HTML Agility Pack, vá em frente, mas não sujeite o mundo a mais invasões de HTML quebradas.

JasonTrue
fonte
27
O HTML Agility Pack não é a resposta para tudo relacionado ao trabalho com HTML (por exemplo, e se você quiser trabalhar apenas com fragmentos do código HTML ?!).
PropellerHead
7
Funciona muito bem com fragmentos de HTML e é a melhor opção para o cenário descrito pelo pôster original. Um Regex, por outro lado, funciona apenas com um HTML idealizado e quebrará com um HTML perfeitamente válido, porque a gramática do HTML não é regular. Se ele estivesse usando Ruby, eu ainda sugeriria nokogiri ou hpricot, ou sopa bonita para Python. É melhor tratar o HTML como HTML, não um fluxo de texto arbitrário sem gramática.
JasonTrue 23/10/09
1
HTML não é uma gramática regular e, portanto, não pode ser analisado apenas com expressões regulares. Você pode usar regexes para lexing, mas não para análise. É realmente assim tão simples. Os linguistas concordariam com isso antes mesmo de o HTML existir.
JasonTrue
20
Isso não é uma questão de opinião. Uma expressão regular pode obter o que você deseja na maioria das vezes, mas falhará em casos muito comuns. Se você puder encontrar um analisador melhor / mais rápido que o HTML Agility Pack, vá em frente, mas não submeta o mundo a mais invasões de HTML quebradas.
JasonTrue
2
Você não pode identificar corretamente as tags HTML de maneira confiável sem analisar o HTML. Você entende toda a gramática do HTML? Veja o truque do mal para se aproximar bastante do sugerido por outras respostas e me diga por que você precisaria manter isso. Fazer um voto negativo porque uma tentativa rápida de hacky funciona para sua entrada de amostra não tornará sua solução correta. Ocasionalmente, usei expressões regulares para gerar relatórios a partir de conteúdo HTML ou para corrigir algumas referências CSS usando correspondência negativa no & gt; limitar a chance de erros, mas fizemos verificações adicionais; não era de propósito geral.
JasonTrue
38

A questão é muito ampla para ser respondida definitivamente. Você está falando sobre remover todas as tags de um documento HTML do mundo real, como uma página da web? Nesse caso, você teria que:

  • remova a declaração <! DOCTYPE ou o prólogo <? xml, se existir
  • remova todos os comentários SGML
  • remova todo o elemento HEAD
  • remova todos os elementos SCRIPT e STYLE
  • Grabthar-sabe-o que com elementos FORM e TABLE
  • remova as tags restantes
  • remova as seqüências <! [CDATA [e]]> das seções CDATA, mas deixe seu conteúdo em paz

Isso está no topo da minha cabeça - tenho certeza de que há mais. Depois de fazer tudo isso, você terminará com palavras, frases e parágrafos juntos em alguns lugares, e grandes pedaços de espaço em branco inútil em outros.

Mas, supondo que você esteja trabalhando apenas com um fragmento e possa simplesmente remover todas as tags, aqui está o regex que eu usaria:

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

A correspondência de cadeias simples e duplas em suas próprias alternativas é suficiente para lidar com o problema de colchetes angulares nos valores de atributo. Não vejo necessidade de corresponder explicitamente os nomes dos atributos e outras coisas dentro da tag, como faz o regex na resposta de Ryan; a primeira alternativa lida com tudo isso.

Caso você esteja se perguntando sobre essas (?>...)construções, são grupos atômicos . Eles tornam o regex um pouco mais eficiente, mas, o mais importante, evitam o retrocesso descontrolado, o que é algo que você sempre deve observar ao misturar quantificadores alternados e aninhados, como eu fiz. Eu realmente não acho que seria um problema aqui, mas sei que se não mencionar, alguém o fará. ;-)

Esse regex não é perfeito, é claro, mas provavelmente é tão bom quanto você precisará.

Alan Moore
fonte
1
Esta é de longe a melhor resposta. Você responde à pergunta do pôster e explica por que uma expressão regular não deve ser usada para a tarefa especificada. Bem feito.
precisa saber é o seguinte
26
Regex regex = new Regex(@"</?\w+((\s+\w+(\s*=\s*(?:"".*?""|'.*?'|[^'"">\s]+))?)+\s*|\s*)/?>", RegexOptions.Singleline);

Fonte

Ryan Emerle
fonte
18

@JasonTrue está correto, que a remoção de tags HTML não deve ser feita por meio de expressões regulares.

É bastante simples remover tags HTML usando HtmlAgilityPack:

public string StripTags(string input) {
    var doc = new HtmlDocument();
    doc.LoadHtml(input ?? "");
    return doc.DocumentNode.InnerText;
}
zzzzBov
fonte
1
Embora eu esteja um pouco atrasado, gostaria de mencionar que isso também funciona em xml, como o produzido pelo Word e outros produtos de escritório. quem já teve a necessidade de lidar com o xml do Word faria bem em usá-lo, porque ajuda muito, especialmente se você precisar retirar tags do conteúdo, exatamente para o que eu precisava.
9788 Steve Pettifer #
Quando tudo mais parecia falhar, esse trecho de código simples salvou o dia. Obrigado!
Ted Krapf 6/03
13

Gostaria de repetir a resposta de Jason, embora às vezes você precise analisar ingenuamente algum HTML e extrair o conteúdo do texto.

Eu precisava fazer isso com um pouco de HTML, criado por um editor de texto rico, sempre divertido e com jogos.

Nesse caso, pode ser necessário remover o conteúdo de algumas tags, bem como apenas as próprias tags.

No meu caso, as tags foram lançadas nesse mix. Alguém pode achar minha implementação (um pouco) menos ingênua um ponto de partida útil.

   /// <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
fonte
1
Além dos problemas óbvios de quebra de linha de plataforma cruzada, ter um quantificador não-guloso é lento quando o conteúdo é delimitado. Use coisas como <xml>.*(?!</xml>)</xml>com o RegexOptions.SingleLinemodificador para os dois primeiros e <[^>]*>para o último. Os primeiros também podem ser combinados por uma alternância capturada no nome da primeira tag e as referências anteriores na aparência negativa e na tag final.
ChrisF
5

tente o método de expressão regular neste 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);
}
Owidat
fonte
3

usa isto..

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

Use este método para remover tags:

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, ""));
}
AnisNoorAli
fonte