Regex для закодированного HTML - PullRequest
2 голосов
/ 17 июля 2009

Я хотел бы создать регулярное выражение, которое будет соответствовать открывающему тегу <a>, содержащему только атрибут href:

<a href="doesntmatter.com">

Должно совпадать с приведенным выше, но не совпадать при добавлении других атрибутов:

<a href="doesntmatter.com" onmouseover="alert('Do something evil with Javascript')">

Обычно это было бы довольно просто, но HTML кодируется. Таким образом, кодируя оба вышеперечисленных, мне нужно регулярное выражение, чтобы соответствовать этому:

&#60;a href&#61;&#34;doesntmatter.com&#34; &#62;

Но не соответствует этому:

&#60;a href&#61;&#34;doesntmatter.com&#34; onmouseover&#61;&#34;alert&#40;&#39;do something evil with javascript.&#39;&#41;&#34; &#62;

Предположим, что весь закодированный HTML является «допустимым» (без странных искаженных трюков XSS) и предположим, что нам не нужно следовать рекомендациям по очистке HTML. Мне просто нужно самое простое регулярное выражение, которое будет соответствовать A) выше, но не B).

Спасибо!

Ответы [ 3 ]

2 голосов
/ 17 июля 2009

Исходное регулярное выражение, которое приходит на ум: /<a href=".*?">/; ленивое выражение (.*?) может использоваться для сопоставления строки между кавычками. Однако, как указано в комментариях, поскольку регулярное выражение привязано символом>, оно также будет соответствовать недопустимому тегу, поскольку сопоставление все еще выполняется.

Чтобы обойти эту проблему, вы можете использовать атомная группировка . Группировка атомов сообщает механизму регулярных выражений: «Как только вы нашли совпадение для этой группы, примите его» - это решит проблему возврата к регулярному выражению и сопоставления второй строки после того, как не будет найдено a> a конца href , Регулярное выражение с атомарной группой будет выглядеть так:

/<a (?>href=".*?")>/

Что будет выглядеть следующим образом при замене символов их HTML-сущностями:

/&#60;a (?>href&#61;&#34;.*?&#34;)&#62;/
1 голос
/ 17 июля 2009

Эй! Я должен был сделать подобное в последнее время. Я рекомендую сначала расшифровать HTML, а затем попытаться получить нужную информацию. Вот мое решение в C #:

private string getAnchor(string data)
    {
        MatchCollection matches;
        string pattern = @"<a.*?href=[""'](?<href>.*?)[""'].*?>(?<text>.*?)</a>";
        Regex myRegex = new Regex(pattern, RegexOptions.Multiline);
        string anchor = "";

        matches = myRegex.Matches(data);

        foreach (Match match in matches)
        {
            anchor += match.Groups["href"].Value.Trim() + "," + match.Groups["text"].Value.Trim();
        }

        return anchor;
    }

Надеюсь, это поможет!

0 голосов
/ 17 июля 2009

Я не вижу, как соответствие одного отличается от другого? Вы просто ищете именно то, что только что написали, делая часть, которая составляет doesntmatter.com, часть, которую вы захватываете. Я думаю, что сопоставление для чего-либо до тех пор, пока &#34; (не &quot;?) Может создать проблему, но вы делаете это так в регулярном выражении:

(?:(?!&#34;).)*

По сути, это означает:

  • Соответствует следующей группе 0 или более раз
    • Неверное совпадение, если следующая строка "&#34;"
    • Соответствует любому символу (кроме новой строки, если не указан DOTALL)

Полное регулярное выражение будет:

/&#60;a href&#61;&#34;(?>(?:[^&]+|(?!&#34;).)*)&#34;&#62;/s

Это более эффективно, чем использование нежадного выражения.

Благодарю Дэниела Вандерслуиса за напоминание о атомной группе ! Здесь он отлично подходит для оптимизации (этот шаблон никогда не может сравниться, если он требует возврата.)

Я также добавил дополнительную группу [^&]+, чтобы не повторять негативный прогноз много раз.

В качестве альтернативы можно использовать притяжательный квантификатор , который по сути делает то же самое (ваш движок регулярных выражений может не поддерживать его):

/&#60;a href&#61;&#34;(?:[^&]+|(?!&#34;).)*+&#34;&#62;/s

Как видите, немного короче.

...