Menggunakan ekspresi reguler C # untuk menghapus tag HTML

139

Bagaimana cara menggunakan ekspresi reguler C # untuk mengganti / menghapus semua tag HTML, termasuk kurung sudut? Dapatkah seseorang tolong bantu saya dengan kode ini?

Keltex
sumber
Anda tidak menunjukkannya, tapi saya menyimpulkan bahwa Anda juga ingin menghapus elemen skrip dan gaya sepenuhnya dan tidak hanya menghapus tag. Jawaban HTML Agility Pack di bawah ini benar untuk menghapus tag, tetapi untuk menghapus skrip dan gaya, Anda juga akan memerlukan sesuatu seperti stackoverflow.com/questions/13441470/…
John
1
Pertanyaan yang diindikasikan sebagai duplikat memiliki banyak informasi (dan Tony Pony!), Tetapi hanya meminta tag pembuka, tidak semua tag. Jadi saya tidak yakin itu duplikat secara teknis. Yang mengatakan, jawabannya sama: jangan.
selamat tinggal

Jawaban:

154

Seperti yang sering dinyatakan sebelumnya, Anda tidak boleh menggunakan ekspresi reguler untuk memproses dokumen XML atau HTML. Mereka tidak berkinerja sangat baik dengan dokumen HTML dan XML, karena tidak ada cara untuk mengekspresikan struktur bersarang secara umum.

Anda bisa menggunakan yang berikut ini.

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

Ini akan berfungsi untuk sebagian besar kasus, tetapi akan ada kasus (misalnya CDATA yang mengandung kurung sudut) di mana ini tidak akan berfungsi seperti yang diharapkan.

Daniel Brückner
sumber
13
Ini adalah implementasi yang naif .. Artinya, <div id = "x <4>"> sayangnya, html valid. Menangani sebagian besar kasus waras ..
Ryan Emerle
8
Seperti yang dinyatakan, saya menyadari bahwa ungkapan ini akan gagal dalam beberapa kasus. Saya bahkan tidak yakin apakah kasus umum dapat ditangani oleh ekspresi reguler tanpa kesalahan.
Daniel Brückner
1
Tidak, ini akan gagal dalam semua kasus! itu serakah.
Jake
13
@ Sandi, mengapa menurut Anda keserakahan adalah masalah? Dengan asumsi kecocokan dimulai pada awal tag HTML yang valid, itu tidak akan pernah melampaui akhir tag itu. Untuk itulah [^>] itu.
Alan Moore
1
@AlanMoore html bukan "bahasa biasa", yaitu Anda tidak dapat mencocokkan semua yang html dengan regex dengan benar. lihat: stackoverflow.com/questions/590747/…
Kache
78

Jawaban yang benar adalah jangan lakukan itu, gunakan HTML Agility Pack .

Diedit untuk menambahkan:

Untuk mencuri tanpa malu-malu dari komentar di bawah ini oleh jesse, dan untuk menghindari dituduh tidak memadai menjawab pertanyaan setelah selama ini, inilah cuplikan sederhana dan dapat diandalkan menggunakan Paket Agility HTML yang bekerja dengan bit HTML yang paling tidak sempurna pun terbentuk dengan sempurna:

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

Ada beberapa kasus yang dapat dipertahankan untuk menggunakan ekspresi reguler untuk parsing HTML, karena HTML tidak dapat diurai dengan benar tanpa kesadaran konteks yang sangat menyakitkan untuk diberikan bahkan di mesin regex nontradisional. Anda bisa mendapatkan sebagian jalan di sana dengan RegEx, tetapi Anda harus melakukan verifikasi manual.

Html Agility Pack dapat memberikan Anda solusi tangguh yang akan mengurangi kebutuhan untuk memperbaiki secara manual penyimpangan yang dapat terjadi akibat memperlakukan HTML secara naif sebagai tata bahasa bebas konteks.

Ekspresi reguler mungkin memberi Anda sebagian besar apa yang paling Anda inginkan, tetapi akan gagal pada kasus yang sangat umum. Jika Anda dapat menemukan parser yang lebih baik / lebih cepat daripada HTML Agility Pack, lakukan itu, tapi tolong jangan membuat dunia peretasan HTML yang lebih rusak.

Jason True
sumber
27
HTML Agility Pack bukanlah jawaban untuk segala sesuatu yang berkaitan dengan bekerja dengan HTML (mis. Bagaimana jika Anda hanya ingin bekerja dengan fragmen kode HTML ?!).
PropellerHead
7
Ini bekerja cukup baik dengan potongan-potongan HTML, dan itu adalah pilihan terbaik untuk skenario yang dijelaskan oleh poster asli. Regex, di sisi lain, hanya bekerja dengan HTML yang diidealisasikan dan akan pecah dengan HTML yang benar-benar valid, karena tata bahasa HTML tidak teratur. Jika dia menggunakan Ruby, saya masih menyarankan nokogiri atau hpricot, atau beautifulsoup untuk Python. Cara terbaik untuk memperlakukan HTML seperti HTML, bukan aliran teks sewenang-wenang tanpa tata bahasa.
JasonTrue
1
HTML bukan tata bahasa biasa, dan karena itu tidak dapat diurai hanya dengan ekspresi reguler. Anda bisa menggunakan regex untuk lexing, tetapi tidak untuk parsing. Sangat sederhana. Ahli bahasa akan menyetujui ini sebelum HTML bahkan ada.
JasonTrue
20
Ini bukan masalah pendapat. Ekspresi reguler mungkin memberi Anda sebagian besar apa yang paling Anda inginkan, tetapi akan gagal pada kasus yang sangat umum. Jika Anda dapat menemukan parser yang lebih baik / lebih cepat daripada HTML Agility Pack, lakukan itu, tapi tolong jangan membuat dunia peretasan HTML yang lebih rusak.
JasonTrue
2
Anda tidak dapat mengidentifikasi tag HTML dengan benar tanpa harus menguraikan HTML. Apakah Anda mengerti semua tata bahasa untuk HTML? Lihat peretasan jahat untuk mendapatkan "cukup dekat" yang disarankan jawaban lain, dan beri tahu saya mengapa Anda harus mempertahankannya. Menurunkan saya karena upaya cepat yang gagal untuk input sampel Anda tidak akan membuat solusi Anda benar. Saya kadang-kadang menggunakan regex laporan menghasilkan dari konten HTML atau untuk memperbaiki beberapa referensi CSS menggunakan pencocokan negatif pada & gt; untuk membatasi kemungkinan kesalahan, tetapi kami melakukan verifikasi tambahan; itu bukan tujuan umum.
JasonTrue
38

Pertanyaannya terlalu luas untuk dijawab secara definitif. Apakah Anda berbicara tentang menghapus semua tag dari dokumen HTML dunia nyata, seperti halaman web? Jika demikian, Anda harus:

  • hapus deklarasi <! DOCTYPE atau prolog <? xml jika ada
  • hapus semua komentar SGML
  • hapus seluruh elemen HEAD
  • hapus semua elemen SCRIPT dan STYLE
  • lakukan Grabthar-know-what dengan elemen FORM dan TABLE
  • hapus tag yang tersisa
  • hapus urutan <! [CDATA [dan]]> dari bagian CDATA tetapi tinggalkan isinya sendiri

Itu hanya di atas kepala saya - saya yakin masih ada lagi. Setelah Anda melakukan semua itu, Anda akan berakhir dengan kata-kata, kalimat dan paragraf berjalan bersama di beberapa tempat, dan potongan besar spasi kosong yang tidak berguna di tempat lain.

Tapi, dengan anggapan Anda bekerja hanya dengan sebuah fragmen dan Anda dapat menghapus hanya dengan menghapus semua tag, inilah regex yang akan saya gunakan:

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

Mencocokkan string dengan kutip tunggal dan ganda dalam alternatifnya sendiri sudah cukup untuk mengatasi masalah kurung sudut dalam nilai atribut. Saya tidak melihat ada kebutuhan untuk secara eksplisit mencocokkan nama atribut dan hal-hal lain di dalam tag, seperti regex dalam jawaban Ryan; alternatif pertama menangani semua itu.

Jika Anda bertanya-tanya tentang (?>...)konstruksi itu, mereka adalah kelompok atom . Mereka membuat regex sedikit lebih efisien, tetapi yang lebih penting, mereka mencegah pelarian mundur, yang merupakan sesuatu yang harus selalu Anda perhatikan ketika Anda mencampur pergantian dan pengukur bersarang seperti yang telah saya lakukan. Saya tidak benar-benar berpikir itu akan menjadi masalah di sini, tetapi saya tahu jika saya tidak menyebutkannya, orang lain akan melakukannya. ;-)

Regex ini tidak sempurna, tentu saja, tetapi mungkin sebaik yang Anda butuhkan.

Alan Moore
sumber
1
Sejauh ini, inilah jawaban terbaik. Anda menjawab pertanyaan poster dan menjelaskan mengapa ungkapan reguler tidak boleh digunakan untuk tugas yang diberikan. Sudah selesai dilakukan dengan baik.
JWilliams
26
Regex regex = new Regex(@"</?\w+((\s+\w+(\s*=\s*(?:"".*?""|'.*?'|[^'"">\s]+))?)+\s*|\s*)/?>", RegexOptions.Singleline);

Sumber

Ryan Emerle
sumber
18

@JasonTrue benar, bahwa pengupasan tag HTML tidak boleh dilakukan melalui ekspresi reguler.

Cukup mudah untuk menghapus tag HTML menggunakan HtmlAgilityPack:

public string StripTags(string input) {
    var doc = new HtmlDocument();
    doc.LoadHtml(input ?? "");
    return doc.DocumentNode.InnerText;
}
zzzzBov
sumber
1
Sementara saya agak terlambat dalam hal ini saya ingin menyebutkan bahwa ini juga berfungsi pada xml seperti yang diproduksi oleh Word dan produk kantor lainnya. siapa pun yang pernah memiliki kebutuhan untuk berurusan dengan Word xml akan melakukannya dengan baik untuk melihat menggunakan ini karena itu banyak membantu, terutama jika Anda perlu menghapus tag dari konten yang persis seperti yang saya butuhkan.
Steve Pettifer
Ketika semuanya tampak gagal, cuplikan kode sederhana ini menyelamatkan hari. Terima kasih!
Ted Krapf
13

Saya ingin mengulangi tanggapan Jason meskipun terkadang Anda perlu mengurai beberapa Html secara naif dan mengeluarkan konten teks.

Saya perlu melakukan ini dengan beberapa Html yang telah dibuat oleh editor teks kaya, selalu menyenangkan dan permainan.

Dalam hal ini, Anda mungkin perlu menghapus konten beberapa tag serta hanya tag itu sendiri.

Dalam kasus saya dan tag dilemparkan ke dalam campuran ini. Seseorang mungkin menganggap implementasi saya (sangat sedikit) kurang naif sebagai titik awal yang berguna.

   /// <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
sumber
1
Terlepas dari masalah linebreak lintas platform yang jelas, memiliki quantifier ungreedy lambat ketika konten dibatasi. Gunakan hal-hal seperti <xml>.*(?!</xml>)</xml>dengan RegexOptions.SingleLinepengubah untuk dua yang pertama dan <[^>]*>yang terakhir. Yang pertama juga dapat digabungkan dengan pergantian yang diambil pada nama tag pertama dan referensi kembali ke sana di lookahead negatif dan tag akhir.
ChrisF
5

coba metode ekspresi reguler di URL ini: 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
sumber
3

Gunakan ini..

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

Gunakan metode ini untuk menghapus 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, ""));
}
AnisNoorAli
sumber