การใช้นิพจน์ทั่วไป C # เพื่อลบแท็ก HTML


139

ฉันจะใช้นิพจน์ทั่วไป C # เพื่อแทนที่ / ลบแท็ก HTML ทั้งหมดรวมถึงวงเล็บเหลี่ยมได้อย่างไร มีคนช่วยฉันด้วยรหัสได้ไหม



คุณไม่ได้ระบุ แต่ฉันคิดว่าคุณต้องการลบองค์ประกอบของสคริปต์และสไตล์ทั้งหมดด้วยและไม่ใช่แค่ลบแท็กออก คำตอบ HTML Agility Pack ด้านล่างนั้นถูกต้องสำหรับการลบแท็ก แต่หากต้องการลบสคริปต์และสไตล์คุณจะต้องใช้stackoverflow.com/questions/13441470/…
John

1
คำถามที่ระบุว่าซ้ำซ้อนมีข้อมูลจำนวนมาก (และ Tony the Pony!) แต่มันขอแค่เปิดแท็กไม่ใช่แท็กทั้งหมด ดังนั้นฉันไม่แน่ใจว่ามันซ้ำซ้อนในทางเทคนิค ที่กล่าวว่าคำตอบคือเหมือนกัน: ไม่
goodeye

คำตอบ:


154

ตามที่ระบุไว้ก่อนหน้านี้คุณไม่ควรใช้นิพจน์ทั่วไปเพื่อประมวลผลเอกสาร XML หรือ HTML พวกเขาทำงานได้ไม่ดีกับเอกสาร HTML และ XML เนื่องจากไม่มีวิธีที่จะแสดงโครงสร้างแบบซ้อนในลักษณะทั่วไป

คุณสามารถใช้สิ่งต่อไปนี้

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

สิ่งนี้จะได้ผลในกรณีส่วนใหญ่ แต่จะมีบางกรณี (เช่น CDATA ที่มีวงเล็บเหลี่ยม) ซึ่งจะไม่ทำงานอย่างที่คาดไว้


13
นี่คือการใช้งานที่ไร้เดียงสา .. นั่นคือ <div id = "x <4>"> น่าเสียดายที่เป็น html ที่ถูกต้อง จัดการกรณีที่มีเหตุผลมากที่สุดแม้ว่า ..
ไรอัน Emerle

8
ตามที่ระบุไว้ฉันทราบว่าการแสดงออกนี้จะล้มเหลวในบางกรณี ฉันไม่แน่ใจว่ากรณีทั่วไปสามารถจัดการโดยนิพจน์ทั่วไปใด ๆ โดยไม่มีข้อผิดพลาดได้หรือไม่
Daniel Brückner

1
ไม่มีสิ่งนี้จะล้มเหลวในทุกกรณี! มันโลภ
Jake

13
@ รหัสทำไมคุณคิดว่าความโลภเป็นปัญหา สมมติว่าการแข่งขันเริ่มต้นที่จุดเริ่มต้นของแท็ก HTML ที่ถูกต้องแท็กนั้นจะไม่ขยายเกินกว่าส่วนท้ายของแท็กนั้น นั่นคือสิ่งที่ [^>] มีไว้สำหรับ
Alan Moore

1
@AlanMoore html ไม่ใช่ "ภาษาปกติ" นั่นคือคุณไม่สามารถจับคู่ทุกอย่างที่เป็น html ที่ถูกต้องกับ regexes ได้ ดู: stackoverflow.com/questions/590747/…
Kache

78

คำตอบที่ถูกต้องคือไม่ทำอย่างนั้นให้ใช้HTML Agility แพ็ค

แก้ไขเพื่อเพิ่ม:

ในการขโมยความคิดเห็นจากเจสซีอย่างไร้ยางอายและเพื่อหลีกเลี่ยงการถูกกล่าวหาว่าตอบคำถามไม่ดีตลอดเวลานี่เป็นตัวอย่างที่ง่ายและเชื่อถือได้โดยใช้ 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 แบบไม่เปลี่ยนตำแหน่ง คุณสามารถไปที่นั่นด้วย RegEx แต่คุณต้องทำการตรวจสอบด้วยตนเอง

Html Agility Pack สามารถมอบโซลูชันที่มีประสิทธิภาพให้กับคุณซึ่งจะช่วยลดความจำเป็นในการแก้ไขความผิดปกติที่อาจเกิดขึ้นจากการใช้ HTML อย่างไร้เดียงสาอย่างไร้เหตุผล

การแสดงออกปกติอาจทำให้คุณได้รับสิ่งที่คุณต้องการเป็นส่วนใหญ่ แต่มันจะล้มเหลวในกรณีที่พบบ่อยมาก หากคุณสามารถหา parser ที่ดีกว่าหรือเร็วกว่า HTML Agility Pack ไปได้เลย แต่โปรดอย่าทำให้โลกนี้แฮ็ค HTML ที่เสียหายมากขึ้น


27
HTML Agility Pack ไม่ใช่คำตอบของทุกสิ่งที่เกี่ยวข้องกับการทำงานกับ HTML (เช่นถ้าคุณต้องการทำงานกับโค้ด HTML เท่านั้น?!)
PropellerHead

7
มันใช้งานได้ดีกับชิ้นส่วน HTML และเป็นตัวเลือกที่ดีที่สุดสำหรับสถานการณ์ที่อธิบายโดยผู้โพสต์ดั้งเดิม ในทางกลับกัน Regex จะทำงานกับ HTML ในอุดมคติเท่านั้นและจะหยุดด้วย HTML ที่ใช้ได้จริงเพราะไวยากรณ์ของ HTML นั้นไม่ปกติ หากเขาใช้ Ruby ฉันยังคงแนะนำ nokogiri หรือ hpricot หรือ beautifulsoup สำหรับ Python เป็นการดีที่สุดที่จะปฏิบัติกับ HTML เช่น HTML ไม่ใช่สตรีมข้อความใด ๆ ที่ไม่มีไวยากรณ์
JasonTrue

1
HTML ไม่ใช่ไวยากรณ์ปกติดังนั้นจึงไม่สามารถแยกวิเคราะห์ได้ด้วยนิพจน์ทั่วไปเท่านั้น คุณสามารถใช้ regexes สำหรับ lexing แต่ไม่ใช่สำหรับการแยก มันง่ายจริงๆ นักภาษาศาสตร์คงจะเห็นด้วยกับเรื่องนี้ก่อนที่จะมี HTML
JasonTrue

20
นี่ไม่ใช่เรื่องของความเห็น การแสดงออกปกติอาจทำให้คุณได้รับสิ่งที่คุณต้องการเป็นส่วนใหญ่ แต่มันจะล้มเหลวในกรณีที่พบบ่อยมาก หากคุณสามารถหา parser ที่ดีกว่าหรือเร็วกว่า HTML Agility Pack ไปได้เลย แต่โปรดอย่าปล่อยให้โลกแฮ็กเกอร์ HTML ที่เสียหายมากกว่านี้
JasonTrue

2
คุณไม่สามารถระบุแท็ก HTML อย่างน่าเชื่อถือได้โดยไม่ต้องแยกวิเคราะห์ HTML คุณเข้าใจไวยากรณ์ทั้งหมดสำหรับ HTML หรือไม่ ดูแฮ็คที่ชั่วร้ายเพื่อให้ "เข้าใกล้" คำตอบอื่น ๆ ที่แนะนำและบอกฉันว่าทำไมคุณต้องรักษามันไว้ การลงคะแนนฉันเนื่องจากความพยายามแฮ็คด่วนทำงานได้สำหรับอินพุตตัวอย่างของคุณจะไม่ทำให้โซลูชันของคุณถูกต้อง ฉันเคยใช้ regexes สร้างรายงานจากเนื้อหา HTML หรือแก้ไขการอ้างอิง CSS โดยใช้การจับคู่เชิงลบใน & gt; เพื่อ จำกัด โอกาสของข้อผิดพลาด แต่เราได้ทำการยืนยันเพิ่มเติม มันไม่ได้มีวัตถุประสงค์ทั่วไป
JasonTrue

38

คำถามกว้างเกินไปที่จะตอบอย่างชัดเจน คุณกำลังพูดถึงการลบแท็กทั้งหมดออกจากเอกสาร HTML ในโลกแห่งความเป็นจริงเช่นหน้าเว็บหรือไม่? ถ้าเป็นเช่นนั้นคุณจะต้อง:

  • ลบการประกาศ <! DOCTYPE หรือ <? xml prolog หากมีอยู่
  • ลบความคิดเห็น SGML ทั้งหมด
  • ลบองค์ประกอบ HEAD ทั้งหมด
  • ลบองค์ประกอบ SCRIPT และ STYLE ทั้งหมด
  • Grabthar-know-what กับองค์ประกอบแบบฟอร์มและตาราง
  • ลบแท็กที่เหลือ
  • ลบลำดับ <! [CDATA [และ]]> ออกจากส่วน CDATA แต่ปล่อยให้เนื้อหาอยู่คนเดียว

นั่นเป็นเพียงส่วนหัวของฉัน - ฉันแน่ใจว่ามีอีก เมื่อคุณทำทุกอย่างเสร็จแล้วคุณจะจบลงด้วยคำประโยคและย่อหน้าที่รวมตัวกันในบางสถานที่และช่องว่างขนาดใหญ่ที่ไร้ประโยชน์ในที่อื่น ๆ

แต่สมมติว่าคุณกำลังทำงานกับส่วนย่อย ๆ และคุณสามารถลบออกได้โดยง่ายเพียงแค่ลบแท็กทั้งหมดนี่คือ regex ที่ฉันจะใช้:

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

การจับคู่สตริงเดี่ยวและเครื่องหมายคำพูดคู่ในทางเลือกของตนเองเพียงพอที่จะจัดการกับปัญหาของวงเล็บเหลี่ยมในค่าแอตทริบิวต์ ฉันไม่เห็นความต้องการใด ๆ ที่จะจับคู่ชื่อแอตทริบิวต์และสิ่งอื่น ๆ ภายในแท็กอย่างชัดเจนเช่นเดียวกับ regex ในคำตอบของ Ryan ทางเลือกแรกจัดการทั้งหมดนั้น

ในกรณีที่คุณสงสัยเกี่ยวกับผู้(?>...)สร้างพวกเขากำลังกลุ่มอะตอม พวกมันทำให้ Regex มีประสิทธิภาพเพิ่มขึ้นเล็กน้อย แต่ที่สำคัญกว่านั้นคือป้องกันการย้อนรอยกลับแบบควบคุมไม่ได้ซึ่งเป็นสิ่งที่คุณควรระวังเมื่อคุณผสมการสับเปลี่ยนและการเรียงซ้อนปริมาณที่ฉันทำ ฉันไม่คิดว่าจะเป็นปัญหาที่นี่ แต่ฉันรู้ว่าถ้าฉันไม่พูดถึงมันคนอื่นจะ ;-)

แน่นอนว่า regex นี้ไม่สมบูรณ์แบบ แต่อาจดีเท่าที่คุณต้องการ


1
นี่คือคำตอบที่ดีที่สุด คุณตอบคำถามของผู้โพสต์และอธิบายว่าทำไมไม่ควรใช้นิพจน์ทั่วไปสำหรับงานที่กำหนด ทำได้ดี.
JWilliams


18

@JasonTrue ถูกต้องการลอกแท็ก HTML นั้นไม่ควรกระทำผ่านการแสดงออกปกติ

การแท็ก HTML โดยใช้ HtmlAgilityPack นั้นค่อนข้างง่าย

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

1
ในขณะที่ฉันสายนี้ฉันอยากจะพูดถึงว่ามันยังทำงานกับ xml เช่นที่ผลิตโดย Word และผลิตภัณฑ์สำนักงานอื่น ๆ ทุกคนที่เคยมีความต้องการที่จะจัดการกับ Word xml จะสามารถใช้สิ่งนี้ได้ดีเพราะมันช่วยได้มากโดยเฉพาะถ้าคุณจำเป็นต้องตัดแท็กจากเนื้อหาซึ่งเป็นสิ่งที่ฉันต้องการ
Steve Pettifer

เมื่อทุกอย่างดูเหมือนจะล้มเหลวตัวอย่างรหัสง่ายๆนี้บันทึกวัน ขอบคุณ!
Ted Krapf

14

ฉันต้องการที่จะสะท้อนการตอบสนองของ Jason แม้ว่าบางครั้งคุณจำเป็นต้องแยกวิเคราะห์ 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"
    }

1
นอกเหนือจากปัญหาการขัดจังหวะการวางแนวข้ามแพลตฟอร์มที่ชัดเจนการมีตัวระบุปริมาณที่ไม่ดีนั้นช้าเมื่อมีการแยกเนื้อหา ใช้สิ่งต่าง ๆ เช่น<xml>.*(?!</xml>)</xml>กับRegexOptions.SingleLineตัวดัดแปลงสำหรับสองตัวแรกและ<[^>]*>ตัวสุดท้าย คนแรกยังสามารถรวมกันโดยการสลับการจับภาพในชื่อแท็กแรกและ backreferences ไปในแท็ก lookahead เชิงลบและแท็กสุดท้าย
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);
}



-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, ""));
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.