Sử dụng biểu thức chính quy C # để xóa thẻ HTML


139

Làm cách nào để sử dụng biểu thức chính quy C # để thay thế / xóa tất cả các thẻ HTML, bao gồm cả dấu ngoặc nhọn? Ai đó có thể vui lòng giúp tôi với mã?



Bạn không chỉ ra điều đó, nhưng tôi suy luận rằng bạn cũng muốn xóa hoàn toàn các thành phần tập lệnh và kiểu và không chỉ xóa thẻ. Câu trả lời HTML Agility Pack bên dưới là chính xác để xóa các thẻ, nhưng để xóa tập lệnh và kiểu, bạn cũng sẽ cần một cái gì đó như stackoverflow.com/questions/13441470/ Lỗi
John

1
Câu hỏi được chỉ ra là trùng lặp có rất nhiều thông tin (và Tony the Pony!), Nhưng nó chỉ yêu cầu mở thẻ chứ không phải tất cả các thẻ. Vì vậy, tôi không chắc chắn về mặt kỹ thuật nó là một bản sao. Điều đó nói rằng, câu trả lời là như nhau: không.
tạm biệt

Câu trả lời:


154

Như thường được nói trước đây, bạn không nên sử dụng các biểu thức thông thường để xử lý các tài liệu XML hoặc HTML. Chúng không hoạt động tốt với các tài liệu HTML và XML, vì không có cách nào để diễn tả các cấu trúc lồng nhau một cách chung chung.

Bạn có thể sử dụng như sau.

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

Điều này sẽ hoạt động trong hầu hết các trường hợp, nhưng sẽ có trường hợp (ví dụ CDATA chứa dấu ngoặc góc) trong đó điều này sẽ không hoạt động như mong đợi.


13
Đây là một triển khai ngây thơ .. Nghĩa là, <div id = "x <4>"> thật không may, html hợp lệ. Xử lý hầu hết các trường hợp lành mạnh ..
Ryan Emerle

8
Như đã nêu, tôi biết rằng biểu hiện này sẽ thất bại trong một số trường hợp. Tôi thậm chí không chắc chắn nếu trường hợp chung có thể được xử lý bởi bất kỳ biểu thức thông thường mà không có lỗi.
Daniel Brückner

1
Không có điều này sẽ thất bại trong mọi trường hợp! nó tham lam.
Jake

13
@Codes, tại sao bạn nghĩ tham lam là một vấn đề? Giả sử trận đấu bắt đầu khi bắt đầu thẻ HTML hợp lệ, nó sẽ không bao giờ mở rộng ra ngoài điểm cuối của thẻ đó. Đó là những gì [^>] dành cho.
Alan Moore

1
@AlanMoore html không phải là "ngôn ngữ thông thường", tức là bạn không thể kết hợp chính xác mọi thứ là html hợp lệ với biểu thức chính quy. xem: stackoverflow.com/questions/590747/ từ
Kache

78

Câu trả lời đúng là không làm điều đó, hãy sử dụng Gói Agility HTML .

Chỉnh sửa để thêm:

Để đánh cắp một cách đáng xấu hổ từ bình luận bên dưới của jlie và để tránh bị buộc tội trả lời không đầy đủ câu hỏi sau tất cả thời gian này, đây là đoạn trích đơn giản, đáng tin cậy bằng cách sử dụng Gói Agility HTML hoạt động với các bit mã hóa hình thành không hoàn hảo nhất của 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());

Có rất ít trường hợp có thể phòng thủ được khi sử dụng biểu thức chính quy để phân tích cú pháp HTML, vì HTML không thể được phân tích cú pháp chính xác mà không có nhận thức ngữ cảnh rất đau đớn để cung cấp ngay cả trong một công cụ regex không điều kiện. Bạn có thể nhận được một phần cách đó với RegEx, nhưng bạn sẽ cần phải xác minh thủ công.

Html Agility Pack có thể cung cấp cho bạn một giải pháp mạnh mẽ giúp giảm nhu cầu sửa lỗi quang sai có thể xảy ra do xử lý HTML một cách ngây thơ như một ngữ pháp không ngữ cảnh.

Một biểu thức thông thường có thể giúp bạn có được hầu hết những gì bạn muốn hầu hết thời gian, nhưng nó sẽ thất bại trong các trường hợp rất phổ biến. Nếu bạn có thể tìm thấy trình phân tích cú pháp tốt hơn / nhanh hơn HTML Agility Pack, hãy tìm nó, nhưng vui lòng không khiến thế giới bị tấn công nhiều hơn với tin tặc HTML.


27
HTML Agility Pack không phải là câu trả lời cho mọi thứ liên quan đến làm việc với HTML (ví dụ: nếu bạn chỉ muốn làm việc với các đoạn mã HTML?!).
Cánh quạt

7
Nó hoạt động khá tốt với các đoạn HTML và đó là lựa chọn tốt nhất cho kịch bản được mô tả bởi poster gốc. Mặt khác, Regex chỉ hoạt động với HTML được lý tưởng hóa và sẽ phá vỡ với HTML hoàn toàn hợp lệ, vì ngữ pháp của HTML không thường xuyên. Nếu anh ta đang sử dụng Ruby, tôi vẫn sẽ gợi ý nokogiri hoặc hpricot, hoặc beautifulsoup cho Python. Tốt nhất là đối xử với HTML như HTML, không phải là một luồng văn bản tùy ý không có ngữ pháp.
JasonTrue

1
HTML không phải là một ngữ pháp thông thường và do đó không thể được phân tích cú pháp chỉ bằng các biểu thức thông thường. Bạn có thể sử dụng regexes cho lexing, nhưng không phải để phân tích cú pháp. Nó thực sự đơn giản. Các nhà ngôn ngữ học đã đồng ý về điều này trước khi HTML tồn tại.
JasonTrue

20
Đây không phải là vấn đề quan điểm. Một biểu thức thông thường có thể giúp bạn có được hầu hết những gì bạn muốn hầu hết thời gian, nhưng nó sẽ thất bại trong các trường hợp rất phổ biến. Nếu bạn có thể tìm thấy trình phân tích cú pháp tốt hơn / nhanh hơn HTML Agility Pack, hãy tìm nó, nhưng vui lòng không khiến thế giới bị tấn công nhiều hơn với tin tặc HTML.
JasonTrue

2
Bạn không thể xác định chính xác các thẻ HTML một cách đáng tin cậy mà không cần phân tích cú pháp HTML. Bạn có hiểu tất cả các ngữ pháp cho HTML không? Xem hack độc ác để có được "khá gần" mà các câu trả lời khác gợi ý, và cho tôi biết lý do tại sao bạn muốn duy trì điều đó. Đánh giá thấp tôi vì một nỗ lực nhanh chóng hacky hoạt động cho đầu vào mẫu của bạn sẽ không làm cho giải pháp của bạn chính xác. Thỉnh thoảng tôi đã sử dụng các biểu thức tạo báo cáo từ nội dung HTML hoặc để sửa một số tham chiếu CSS bằng cách sử dụng kết hợp phủ định trên & gt; để hạn chế khả năng xảy ra lỗi, nhưng chúng tôi đã xác minh bổ sung; đó không phải là mục đích chung.
JasonTrue

38

Câu hỏi quá rộng để được trả lời dứt khoát. Bạn đang nói về việc xóa tất cả các thẻ khỏi tài liệu HTML trong thế giới thực, như trang web? Nếu vậy, bạn sẽ phải:

  • xóa khai báo <! DOCTYPE hoặc <? xml prolog nếu chúng tồn tại
  • xóa tất cả các bình luận SGML
  • loại bỏ toàn bộ phần tử CHÍNH
  • xóa tất cả các phần tử SCRIPT và STYLE
  • Grabthar-know-what với các yếu tố FORM và TABLE
  • xóa các thẻ còn lại
  • xóa các chuỗi <! [CDATA [và]]> khỏi các phần CDATA nhưng chỉ để lại nội dung của chúng

Đó chỉ là trên đỉnh đầu của tôi - Tôi chắc chắn có nhiều hơn nữa. Khi bạn đã thực hiện tất cả những điều đó, bạn sẽ kết thúc bằng các từ, câu và đoạn văn chạy cùng nhau ở một số nơi và các khoảng trống lớn vô dụng ở những nơi khác.

Nhưng, giả sử bạn đang làm việc chỉ với một đoạn và bạn có thể thoát khỏi chỉ bằng cách xóa tất cả các thẻ, đây là regex tôi sẽ sử dụng:

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

Việc kết hợp các chuỗi trích dẫn đơn và kép trong các lựa chọn thay thế của chúng là đủ để giải quyết vấn đề về dấu ngoặc góc trong các giá trị thuộc tính. Tôi không thấy bất kỳ nhu cầu nào phải khớp rõ ràng tên thuộc tính và các thứ khác trong thẻ, giống như biểu thức chính thức trong câu trả lời của Ryan; sự thay thế đầu tiên xử lý tất cả điều đó.

Trong trường hợp bạn đang tự hỏi về những (?>...)cấu trúc đó, chúng là các nhóm nguyên tử . Chúng làm cho regex hiệu quả hơn một chút, nhưng quan trọng hơn, chúng ngăn chặn việc quay lại chạy trốn, đó là điều bạn nên luôn luôn đề phòng khi trộn lẫn các bộ lượng tử xen kẽ và lồng nhau như tôi đã làm. Tôi thực sự không nghĩ rằng đó sẽ là một vấn đề ở đây, nhưng tôi biết nếu tôi không đề cập đến nó, người khác sẽ làm. ;-)

Regex này không hoàn hảo, tất nhiên, nhưng nó có thể tốt như bạn cần.


1
Đây là câu trả lời tốt nhất. Bạn trả lời câu hỏi của người gửi và giải thích tại sao không nên sử dụng biểu thức chính quy cho tác vụ đã cho. Làm tốt.
JWilliams

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

Nguồn


18

@JasonTrue là chính xác, việc tước thẻ HTML không nên được thực hiện thông qua các biểu thức thông thường.

Khá đơn giản để loại bỏ các thẻ HTML bằng HtmlAgilityPack:

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

1
Trong khi tôi hơi muộn về điều này, tôi muốn đề cập rằng nó cũng hoạt động trên xml, chẳng hạn như được sản xuất bởi Word và các sản phẩm văn phòng khác. Bất cứ ai từng có nhu cầu xử lý Word xml đều có thể xem xét việc sử dụng này vì nó giúp ích rất nhiều, đặc biệt là nếu bạn cần loại bỏ các thẻ khỏi nội dung chính xác là những gì tôi cần.
Steve Pettifer

Khi tất cả những thứ khác dường như thất bại, đoạn mã đơn giản này đã lưu lại ngày. Cảm ơn!
Ted Krapf

13

Tôi muốn lặp lại phản hồi của Jason mặc dù đôi khi bạn cần ngây thơ phân tích một số Html và lấy ra nội dung văn bản.

Tôi cần phải làm điều này với một số Html đã được tạo bởi một trình soạn thảo văn bản phong phú, luôn vui vẻ và trò chơi.

Trong trường hợp này, bạn có thể cần phải xóa nội dung của một số thẻ cũng như chính các thẻ đó.

Trong trường hợp của tôi và các thẻ đã được ném vào hỗn hợp này. Một số người có thể thấy việc triển khai ít ngây thơ của tôi (một chút) là điểm khởi đầu hữu ích.

   /// <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
Ngoài các vấn đề về đường chéo nền tảng rõ ràng, việc có một bộ lượng hóa vô duyên là chậm khi nội dung được phân định. Sử dụng những thứ như <xml>.*(?!</xml>)</xml>với công cụ RegexOptions.SingleLinesửa đổi cho hai cái đầu tiên và <[^>]*>cái cuối cùng. Những cái đầu tiên cũng có thể được kết hợp bởi một sự thay thế được chụp trong tên thẻ đầu tiên và phản hồi cho nó trong cái nhìn tiêu cực và thẻ cuối cùng.
ChrisF

5

thử phương thức biểu thức chính quy tại URL này: 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

dùng cái này..

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


-1

Sử dụng phương pháp này để xóa thẻ:

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, ""));
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.