текст - удалить html теги c#




Как фильтровать все теги HTML, кроме определенного белого списка? (5)

Атрибуты - основная проблема с использованием регулярных выражений, чтобы попытаться работать с HTML. Учитывайте огромное количество потенциальных атрибутов и тот факт, что большинство из них являются необязательными, а также тот факт, что они могут отображаться в любом порядке, и тот факт, что «>» является юридическим символом в значениях цитируемых атрибутов. Когда вы начинаете пытаться учитывать все это, регулярное выражение, с которым вам нужно будет справиться, быстро станет неуправляемым.

Вместо этого я хотел бы использовать HTML-парсер на основе событий или тот, который дает вам дерево DOM, через которое вы можете пройти.

Это для .NET. IgnoreCase установлен, а MultiLine не установлен.

Обычно я порядочный в регулярном выражении, возможно, я бегу на кофеине ...

Пользователям разрешено вводить объекты с кодировкой HTML (<lt ;, <amp ;, и т. Д.) И использовать следующие теги HTML:

u, i, b, h3, h4, br, a, img

Самозакрывающиеся <br/> и <img /> разрешены с дополнительным пространством или без него, но не требуются.

Я хочу:

  1. Стрите все начальные и конечные теги HTML, кроме перечисленных выше.
  2. Удалите атрибуты из остальных тегов, за исключением того, что привязки могут иметь href.

Мой шаблон поиска (заменен пустой строкой):

<(?!i|b|h3|h4|a|img|/i|/b|/h3|/h4|/a|/img)[^>]+>

Кажется, это зачищает все, кроме начальных и конечных тегов, которые я хочу, но есть три проблемы:

  1. Необходимость включения версии конечного тега для каждого разрешенного тега является уродливой.
  2. Атрибуты сохраняются. Может ли это произойти в одной замене?
  3. Теги, начинающиеся с разрешенных имен тегов, проскальзывают. Например, «<abbrev>» и «<iframe>».

Следующий предложенный шаблон не выделяет теги, у которых нет атрибутов.

</?(?!i|b|h3|h4|a|img)\b[^>]*>

Как упоминалось ниже, «>» является законным в значении атрибута, но можно с уверенностью сказать, что я не буду этого поддерживать. Кроме того, не будет блоков CDATA и т. Д., О которых нужно беспокоиться. Просто немного HTML.

Ответ Loophole - лучший, пока что, спасибо! Вот его образец (надеясь, что PRE работает лучше для меня):

static string SanitizeHtml(string html)
{
    string acceptable = "script|link|title";
    string stringPattern = @"</?(?(?=" + acceptable + @")notag|[a-zA-Z0-9]+)(?:\s[a-zA-Z0-9\-]+=?(?:([""']?).*?\1?)?)*\s*/?>";
    return Regex.Replace(html, stringPattern, "sausage");
}

Я думаю, что некоторые мелкие хитрости могут быть приняты к этому ответу:

  1. Я думаю, что это можно было бы изменить, чтобы фиксировать простые комментарии HTML (те, которые сами не содержат тегов), добавляя «! -» к «приемлемой» переменной и делая небольшое изменение в конце выражения, чтобы разрешить необязательный трейлинг "\ S--".

  2. Я думаю, что это сломается, если между атрибутами есть несколько пробельных символов (например: сильно отформатированный HTML с разрывами строк и вкладками между атрибутами).

Edit 2009-07-23: Вот окончательное решение, с которым я пошел (в VB.NET):

 Dim AcceptableTags As String = "i|b|u|sup|sub|ol|ul|li|br|h2|h3|h4|h5|span|div|p|a|img|blockquote"
 Dim WhiteListPattern As String = "</?(?(?=" & AcceptableTags & _
      ")notag|[a-zA-Z0-9]+)(?:\s[a-zA-Z0-9\-]+=?(?:([""']?).*?\1?)?)*\s*/?>"
 html = Regex.Replace(html, WhiteListPattern, "", RegExOptions.Compiled)

Предостережение заключается в том, что атрибут HREF тегов A по-прежнему очищается, что не является идеальным.


Вот функция, которую я написал для этой задачи:

static string SanitizeHtml(string html)
{
    string acceptable = "script|link|title";
    string stringPattern = @"</?(?(?=" + acceptable + @")notag|[a-zA-Z0-9]+)(?:\s[a-zA-Z0-9\-]+=?(?:(["",']?).*?\1?)?)*\s*/?>";
    return Regex.Replace(html, stringPattern, "sausage");
}

Изменить: по какой-то причине я опубликовал исправление к моему предыдущему ответу в виде отдельного ответа, поэтому я их объединяю здесь.

Я немного объясню регулярное выражение, потому что он немного длинный.

Первая часть соответствует открытой скобке и 0 или 1 слэшам (в случае, если это близкий тег).

Затем вы видите конструкцию if-then с перспективой. (? (? = SomeTag) then | else) Я проверяю, является ли следующая часть строки одним из допустимых тегов. Вы можете видеть, что я объединяю строку регулярных выражений с допустимой переменной, которая является допустимыми именами тегов, разделенными вертикальной планкой, так что любое из этих условий будет соответствовать. Если это совпадение, вы можете увидеть, что я ввел слово «notag», потому что никакой тег не соответствовал бы этому, и если он будет приемлемым, я хочу оставить его в покое. В противном случае я перехожу к части else, где я сопоставляю любое имя тега [az, AZ, 0-9] +

Далее, я хочу совместить 0 или более атрибутов, которые, как я полагаю, находятся в форме attribute = "value". поэтому теперь я группирую эту часть, представляющую атрибут, но я использую:: для предотвращения захвата этой группы для скорости: (?: \ s [az, AZ, 0-9, -] + =? (?: ([" ", ']?). ? \ 1?))

Здесь я начинаю с символа пробела, который будет находиться между тегами и именами атрибутов, а затем соответствует имени атрибута: [az, AZ, 0-9, -] +

Затем я сопоставляю знак равенства, а затем либо цитирую. Я группирую цитату, чтобы она была захвачена, и я могу сделать backreference позже \ 1, чтобы соответствовать одному типу цитаты. В промежутке между этими двумя кавычками вы можете видеть, что я использую период, чтобы соответствовать чему-либо, однако я использую ленивую версию *? вместо жадной версии *, чтобы она соответствовала только следующей цитате, которая закончила бы это значение.

Затем мы помещаем * после закрытия групп с круглыми скобками, чтобы они соответствовали нескольким комбинациям attirbute / value (или none). В последнем случае мы сопоставляем пробелы с \ s и 0 или 1 завершающие слэши в теге для тегов самозакрывания стиля xml.

Вы можете видеть, что я заменяю теги колбасой, потому что я голоден, но вы можете заменить их пустой строкой, чтобы просто очистить их.


Это хороший рабочий пример фильтрации html-тегов:

Sanitize HTML


Я думаю, что я изначально собирался сделать значения необязательными, но не прошел, поскольку я вижу, что добавил ? после знака равенства и сгруппировал часть значения совпадения. Давайте добавим ? после этой группы (отмеченной каротой), чтобы сделать ее необязательной в матче. Я не в своем компиляторе прямо сейчас, но посмотрите, работает ли это:

@"</?(?(?=" + acceptable + @")notag|[a-z,A-Z,0-9]+)(?:\s[a-z,A-Z,0-9,\-]+=?(?:(["",']?).*?\1?)?)*\s*/?>";
                                                                                             ^

    /// <summary>
    /// Trims the ignoring spacified tags
    /// </summary>
    /// <param name="text">the text from which html is to be removed</param>
    /// <param name="isRemoveScript">specify if you want to remove scripts</param>
    /// <param name="ignorableTags">specify the tags that are to be ignored while stripping</param>
    /// <returns>Stripped Text</returns>
    public static string StripHtml(string text, bool isRemoveScript, params string[] ignorableTags)
    {
        if (!string.IsNullOrEmpty(text))
        {
            text = text.Replace("&lt;", "<");
            text = text.Replace("&gt;", ">");
            string ignorePattern = null;

            if (isRemoveScript)
            {
                text = Regex.Replace(text, "<script[^<]*</script>", string.Empty, RegexOptions.IgnoreCase);
            }
            if (!ignorableTags.Contains("style"))
            {
                text = Regex.Replace(text, "<style[^<]*</style>", string.Empty, RegexOptions.IgnoreCase);
            }
            foreach (string tag in ignorableTags)
            {
                //the character b spoils the regex so replace it with strong
                if (tag.Equals("b"))
                {
                    text = text.Replace("<b>", "<strong>");
                    text = text.Replace("</b>", "</strong>");
                    if (ignorableTags.Contains("strong"))
                    {
                        ignorePattern = string.Format("{0}(?!strong)(?!/strong)", ignorePattern);
                    }
                }
                else
                {
                    //Create ignore pattern fo the tags to ignore
                    ignorePattern = string.Format("{0}(?!{1})(?!/{1})", ignorePattern, tag);
                }

            }
            //finally add the ignore pattern into regex <[^<]*> which is used to match all html tags
            ignorePattern = string.Format(@"<{0}[^<]*>", ignorePattern);
            text = Regex.Replace(text, ignorePattern, "", RegexOptions.IgnoreCase);
        }

        return text;
    }






regex