Використання регулярних виразів C # для видалення тегів HTML


139

Як використовувати регулярний вираз C # для заміни / видалення всіх тегів HTML, включаючи кутові дужки? Може хтось, будь ласка, допоможе мені з кодом?



Ви цього не вказуєте, але я роблю висновок, що ви також хочете повністю видалити елементи сценарію та стилю, а не просто видалити тег. Відповідь пакета HTML Agility нижче наведена правильно для видалення тегів, але для видалення сценарію та стилю вам також знадобиться щось на зразок stackoverflow.com/questions/13441470/…
Джон

1
Питання, вказане як дублікат, містить багато інформації (і Тоні Поні!), Але воно попросило лише відкрити теги, а не всі теги. Тож я не впевнений, що це технічно дублікат. Однак, відповідь однаковий: не варто.
goodeye

Відповіді:


154

Як часто говорилося раніше, не слід використовувати регулярні вирази для обробки XML або HTML документів. Вони не дуже добре працюють з документами HTML і XML, тому що немає можливості виразити вкладені структури загальним способом.

Ви можете використовувати наступне.

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

Це буде працювати в більшості випадків, але будуть випадки (наприклад, CDATA, що містять кутові дужки), коли це не буде працювати, як очікувалося.


13
Це наївна реалізація .. Тобто <div id = "x <4>"> на жаль, дійсний html. Хоча це
стосується і найрозумніших

8
Як було сказано, мені відомо, що в деяких випадках цей вираз зазнає невдачі. Я навіть не впевнений, чи може загальний випадок вирішуватися будь-яким регулярним виразом без помилок.
Даніель Брюкнер

1
Ні, це не вийде у всіх випадках! її жадібна.
Джейк

13
@Cipher, чому ти вважаєш, що жадібність - це проблема? Якщо припустити, що збіг починається з початку дійсного тегу HTML, він ніколи не поширюється за межі кінця цього тегу. Ось для чого [^>].
Алан Мур

1
@AlanMoore html не є "звичайною мовою", тобто ви не можете правильно зіставити все, що є дійсним html, з регексами. див .: stackoverflow.com/questions/590747/…
Kache

78

Правильна відповідь - не робіть цього, використовуйте пакет пакету спритності HTML .

Відредаговано, щоб додати:

Щоб безсоромно вкрастись від коментаря, поданого нижче від jesse, і уникнути звинувачення у неадекватній відповіді на питання після закінчення цього часу, ось простий надійний фрагмент із використанням пакету HTML Agility, який працює навіть з найбільш недосконало сформованими, примхливими бітами 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, але вам потрібно буде зробити перевірку вручну.

Пакет спритності Html може надати вам надійне рішення, яке зменшить потребу вручну виправити відхилення, які можуть бути наслідком наївного поводження з HTML як граматики без контексту.

Звичайний вираз може отримати в основному те, чого ви хочете більшу частину часу, але це не вдасться у дуже поширених випадках. Якщо ви можете знайти кращий / швидший синтаксичний аналізатор, ніж HTML Agility Pack, займіться цим, але, будь ласка, не піддавайте світу більш зламаного HTML-хакерства.


27
Пакет спритності HTML - це не відповідь на все, що стосується роботи з HTML (наприклад, що робити, якщо ви хочете працювати лише з фрагментами HTML-коду ?!).
PropellerHead

7
Він досить добре працює з фрагментами HTML, і це найкращий варіант для сценарію, описаного в оригінальному плакаті. Regex, з іншого боку, працює лише з ідеалізованим HTML і розірветься з ідеально правильним HTML, оскільки граматика HTML не є регулярною. Якби він використовував Ruby, я все-таки запропонував би nokogiri або hpricot, або красивий набір для Python. Найкраще трактувати HTML як HTML, а не якийсь довільний текстовий потік без граматики.
JasonTrue

1
HTML не є звичайною граматикою, і тому його не можна розбирати лише регулярними виразами. Ви можете використовувати шрифти для лексингу, але не для розбору. Це дійсно так просто. Лінгвісти погодились би на це ще до існування HTML.
JasonTrue

20
Це не питання думки. Звичайний вираз може отримати в основному те, чого ви хочете більшу частину часу, але це не вдасться у дуже поширених випадках. Якщо ви можете знайти кращий / швидший синтаксичний аналізатор, ніж HTML Agility Pack, займіться цим, але, будь ласка, не піддавайте світу більш зламаного HTML-хакерства.
JasonTrue

2
Ви не можете правильно ідентифікувати теги HTML без аналізу HTML. Ви розумієте всю граматику для HTML? Дивіться злий хак, щоб отримати "досить близько", що підказують інші відповіді, і скажіть мені, чому ви хочете це підтримувати. Відмовляючись від мене, оскільки швидка спроба працює для вашого введення зразка, не буде зробити ваше рішення правильним. Іноді я використовував регулярні вирази для створення звітів із вмісту HTML або для виправлення деяких посилань CSS, використовуючи негативну відповідність на & gt; щоб обмежити ймовірність помилок, але ми зробили додаткові перевірки; це не було загальним призначенням.
JasonTrue

38

Питання занадто широке, щоб відповісти остаточно. Ви говорите про видалення всіх тегів із реального HTML-документа, як-от веб-сторінки? Якщо так, вам доведеться:

  • видаліть <! DOCTYPE декларацію або <? xml пролог, якщо вони існують
  • видалити всі коментарі SGML
  • видаліть весь елемент HEAD
  • видаліть усі елементи SCRIPT і STYLE
  • робити Grabthar-знає-що з елементами FORM і TABLE
  • видаліть решту тегів
  • видаліть <! [CDATA [і]]> послідовності з розділів CDATA, але залиште їх вміст у спокої

Це просто з моєї голови - я впевнений, що є більше. Після того, як ви все зробите, ви закінчите, що слова, речення та абзаци в деяких місцях збираються разом, а в інших - великі шматки непотрібних пробілів.

Але, якщо припустити, що ви працюєте з лише фрагментом, і ви можете піти, просто видаливши всі теги, ось я б застосував регулярний вираз:

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

Збіг однорядних та подвійних цитувань рядків у власних альтернативах є достатнім для вирішення проблеми кутових дужок у значеннях атрибутів. Я не бачу ніякої необхідності явно збігати імена атрибутів та інші речі всередині тегу, як, наприклад, регекс у відповіді Райана; перша альтернатива обробляє все це.

Якщо вам цікаво про ці (?>...)конструкції, вони є атомними групами . Вони роблять регулярний вираз трохи ефективнішим, але що ще важливіше, вони запобігають уникнути зворотного відстеження, на що завжди слід стежити, коли ви змішуєте чергування та вкладені квантори, як я це робив. Я не думаю, що це буде проблемою, але я знаю, що якщо я не згадаю про це, хтось інший зробить це. ;-)

Цей регулярний вираз, звичайно, не є ідеальним, але він, мабуть, настільки ж хороший, як вам коли-небудь знадобиться.


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, добре би розглянути це використання, тому що це дуже допомагає, особливо якщо вам потрібно зняти теги з контенту, саме для цього я і потребував.
Стів Петтіфер

Коли все інше здавалося невдалим, цей простий фрагмент коду врятував день. Дякую!
Тед Крапф

14

Я хотів би повторити відповідь Джейсона, хоча іноді потрібно наївно проаналізувати якийсь 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модифікатором для перших двох і <[^>]*>для останнього. Перші також можуть бути об'єднані зафіксованим чергуванням у назві першого тегу та зворотними посиланнями до нього в негативному пошуку та заключному тезі.
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, ""));
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.