Utilizzo delle espressioni regolari C # per rimuovere i tag HTML


139

Come uso l'espressione regolare C # per sostituire / rimuovere tutti i tag HTML, comprese le parentesi angolari? Qualcuno può aiutarmi con il codice, per favore?



Non lo indichi, ma sto deducendo che vuoi anche rimuovere completamente gli script e gli elementi di stile e non solo rimuovere il tag. La risposta HTML Agility Pack di seguito è corretta per la rimozione dei tag, ma per rimuovere lo script e lo stile, avrai anche bisogno di qualcosa come stackoverflow.com/questions/13441470/…
John

1
La domanda indicata come duplicata contiene molte informazioni (e Tony il Pony!), Ma ha richiesto solo l'apertura dei tag, non tutti i tag. Quindi non sono sicuro che sia tecnicamente un duplicato. Detto questo, la risposta è la stessa: non farlo.
addio

Risposte:


154

Come spesso affermato in precedenza, non è necessario utilizzare espressioni regolari per elaborare documenti XML o HTML. Non si comportano molto bene con i documenti HTML e XML, perché non c'è modo di esprimere strutture nidificate in modo generale.

È possibile utilizzare quanto segue.

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

Funzionerà nella maggior parte dei casi, ma ci saranno casi (ad esempio CDATA contenenti parentesi angolari) in cui ciò non funzionerà come previsto.


13
Questa è un'implementazione ingenua. Cioè, <div id = "x <4>"> è sfortunatamente, html valido. Gestisce i casi più sani però ...
Ryan Emerle il

8
Come detto, sono consapevole che questa espressione fallirà in alcuni casi. Non sono nemmeno sicuro che il caso generale possa essere gestito da qualsiasi espressione regolare senza errori.
Daniel Brückner,

1
No, questo fallirà in tutti i casi! è avido.
Jake,

13
@Cipher, perché pensi che l'avidità sia un problema? Supponendo che la corrispondenza inizi all'inizio di un tag HTML valido, non si estenderà mai oltre la fine di quel tag. Ecco a cosa serve [^>].
Alan Moore,

1
@AlanMoore html non è un "linguaggio normale", cioè non puoi abbinare correttamente tutto ciò che è html valido con regex. vedi: stackoverflow.com/questions/590747/...
Kache

78

La risposta corretta è non farlo, usa HTML Agility Pack .

Modificato per aggiungere:

Per sottrarre spudoratamente dal commento qui sotto di jesse ed evitare di essere accusato di rispondere inadeguatamente alla domanda dopo tutto questo tempo, ecco un semplice e affidabile snippet che utilizza HTML Agility Pack che funziona anche con bit capricciosi di HTML formati in modo più imperfetto:

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

Esistono pochissimi casi difendibili per l'uso di un'espressione regolare per l'analisi dell'HTML, poiché l'HTML non può essere analizzato correttamente senza una consapevolezza del contesto che è molto dolorosa da fornire anche in un motore regex non tradizionale. Puoi arrivare a metà strada con un RegEx, ma dovrai fare delle verifiche manuali.

Html Agility Pack può fornirti una soluzione solida che ridurrà la necessità di correggere manualmente le aberrazioni che possono derivare dal trattamento ingenuo dell'HTML come una grammatica senza contesto.

Un'espressione regolare può darti principalmente quello che vuoi per la maggior parte del tempo, ma fallirà in casi molto comuni. Se riesci a trovare un parser migliore / più veloce di HTML Agility Pack, provalo, ma per favore non sottoporre il mondo a hacker HTML più rotti.


27
HTML Agility Pack non è la risposta a tutto ciò che riguarda l'utilizzo dell'HTML (ad esempio cosa succede se si desidera lavorare solo con frammenti del codice HTML ?!).
Elica:

7
Funziona abbastanza bene con frammenti di HTML ed è l'opzione migliore per lo scenario descritto dal poster originale. Un Regex, d'altra parte, funziona solo con un HTML idealizzato e si romperà con un HTML perfettamente valido, perché la grammatica dell'HTML non è regolare. Se stesse usando Ruby, avrei comunque suggerito nokogiri o hpricot o beautifulsoup per Python. È meglio trattare HTML come HTML, non un flusso di testo arbitrario senza grammatica.
JasonTrue

1
L'HTML non è una grammatica regolare e pertanto non può essere analizzato solo con espressioni regolari. È possibile utilizzare regex per il lexing, ma non per l'analisi. È davvero così semplice. I linguisti lo avrebbero concordato prima ancora che esistesse l'HTML.
JasonTrue,

20
Questa non è una questione di opinione. Un'espressione regolare può farti ottenere ciò che desideri per la maggior parte del tempo, ma fallirà in casi molto comuni. Se riesci a trovare un parser migliore / più veloce di HTML Agility Pack, provalo, ma per favore non sottoporre il mondo a hacker HTML più rotti.
JasonTrue,

2
Non è possibile identificare correttamente i tag HTML in modo affidabile senza analizzare HTML. Capisci tutta la grammatica per HTML? Guarda l'hack malvagio per avvicinarti "abbastanza vicino" che altre risposte suggeriscono e dimmi perché dovresti mantenerlo. Downvoting me perché un tentativo veloce hacky per l'input di esempio non renderà la soluzione corretta. Ho usato occasionalmente regex per generare report dal contenuto HTML o per correggere alcuni riferimenti CSS usando la corrispondenza negativa su & gt; per limitare la possibilità di errori, ma abbiamo effettuato ulteriori verifiche; non era uno scopo generale.
JasonTrue

38

La domanda è troppo ampia per essere risolta definitivamente. Stai parlando di rimuovere tutti i tag da un documento HTML del mondo reale, come una pagina web? In tal caso, dovresti:

  • rimuovere la dichiarazione <! DOCTYPE o il prologo <? xml se esistono
  • rimuovi tutti i commenti SGML
  • rimuovere l'intero elemento HEAD
  • rimuovere tutti gli elementi SCRIPT e STYLE
  • Grabthar-sa-cosa con gli elementi FORM e TABLE
  • rimuovere i tag rimanenti
  • rimuovere le sequenze <! [CDATA [e]]> dalle sezioni CDATA ma lasciare solo il loro contenuto

Questo è appena fuori dalla mia testa - Sono sicuro che c'è di più. Una volta che hai fatto tutto ciò, finirai con parole, frasi e paragrafi che corrono insieme in alcuni punti e grossi pezzi di spazio bianco inutile in altri.

Ma supponendo che tu stia lavorando con solo un frammento e che tu possa cavartela semplicemente rimuovendo tutti i tag, ecco la regex che userei:

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

La corrispondenza di stringhe tra virgolette singole e doppie nelle loro alternative è sufficiente per affrontare il problema delle parentesi angolari nei valori degli attributi. Non vedo alcun bisogno di abbinare esplicitamente i nomi degli attributi e altre cose all'interno del tag, come fa la regex nella risposta di Ryan; la prima alternativa gestisce tutto ciò.

Nel caso ti stia chiedendo di quei (?>...)costrutti, sono gruppi atomici . Rendono il regex un po 'più efficiente, ma, cosa più importante, impediscono il backtracking in fuga, che è qualcosa a cui dovresti sempre fare attenzione quando mescoli alternanza e quantificatori annidati come ho fatto. Non penso davvero che sarebbe un problema qui, ma so che se non lo menzionassi, lo farà qualcun altro. ;-)

Questo regex non è perfetto, ovviamente, ma è probabilmente buono come non ne avrai mai bisogno.


1
Questa è di gran lunga la risposta migliore. Rispondi alla domanda del poster e spiega perché un'espressione regolare non deve essere utilizzata per l'attività specificata. Molto bene.
JWilliams,

26
Regex regex = new Regex(@"</?\w+((\s+\w+(\s*=\s*(?:"".*?""|'.*?'|[^'"">\s]+))?)+\s*|\s*)/?>", RegexOptions.Singleline);

fonte


18

@JasonTrue ha ragione, che lo stripping dei tag HTML non dovrebbe essere fatto tramite espressioni regolari.

È abbastanza semplice rimuovere i tag HTML usando HtmlAgilityPack:

public string StripTags(string input) {
    var doc = new HtmlDocument();
    doc.LoadHtml(input ?? "");
    return doc.DocumentNode.InnerText;
}

1
Anche se sono un po 'in ritardo, vorrei ricordare che funziona anche su XML come quello prodotto da Word e altri prodotti per ufficio. chiunque abbia mai avuto la necessità di gestire Word xml farebbe bene a usarlo perché aiuta molto, specialmente se è necessario rimuovere i tag dal contenuto che è esattamente quello di cui avevo bisogno.
Steve Pettifer

Quando tutto il resto sembrava fallire, questo semplice frammento di codice ha salvato la giornata. Grazie!
Ted Krapf il

14

Vorrei fare eco alla risposta di Jason, anche se a volte è necessario analizzare ingenuamente un po 'di HTML e estrarre il contenuto del testo.

Ho dovuto farlo con un po 'di HTML che era stato creato da un ricco editor di testi, sempre divertente e con giochi.

In questo caso potrebbe essere necessario rimuovere il contenuto di alcuni tag e solo i tag stessi.

Nel mio caso e tag sono stati gettati in questo mix. Qualcuno potrebbe trovare la mia (molto leggermente) meno ingenua implementazione un utile punto di partenza.

   /// <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"
    }

1
A parte ovvi problemi di interruzione di riga multipiattaforma, avere un quantificatore non gradito è lento quando il contenuto è delimitato. Usa cose come <xml>.*(?!</xml>)</xml>con il RegexOptions.SingleLinemodificatore per i primi due e <[^>]*>per gli ultimi. I primi possono anche essere combinati da un'alternanza acquisita nel nome del primo tag e riferimenti a esso nel lookahead negativo e nel tag finale.
ChrisF,

5

prova il metodo delle espressioni regolari a questo 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

Usa questo..

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


-1

Utilizzare questo metodo per rimuovere i tag:

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, ""));
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.