2

我想创建一个正则表达式,它将匹配<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)。

谢谢!

4

3 回答 3

2

想到的最初的正则表达式是/<a href=".*?">/; 惰性表达式 ( .*?) 可用于匹配引号之间的字符串。但是,正如评论中指出的那样,因为正则表达式由 > 锚定,它也会匹配无效标签,因为仍然进行匹配。

为了解决这个问题,您可以使用atomic grouping。原子分组告诉正则表达式引擎,“一旦找到该组的匹配项,就接受它”——这将解决正则表达式在没有找到 a > a href 的结尾后返回并匹配第二个字符串的问题. 带有原子组的正则表达式如下所示:

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

将字符替换为 HTML 实体时如下所示:

/&#60;a (?>href&#61;&#34;.*?&#34;)&#62;/
于 2009-07-17T13:45:45.687 回答
1

嘿!我最近不得不做类似的事情。我建议先解码 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;
    }

我希望这会有所帮助!

于 2009-07-17T13:49:14.760 回答
0

我看不出匹配一个与另一个有什么不同?你只是在寻找你刚刚写的东西,制作doesntmatter.com你捕捉的部分。我想匹配任何东西,直到&#34;(不是&quot;?)可能会出现问题,但你在正则表达式中这样做:

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

它本质上意味着:

  • 匹配以下组 0 次或多次
    • 如果以下字符串是,则匹配失败"&#34;"
    • 匹配任何字符(除非指定了 DOTALL,否则换行除外)

完整的正则表达式将是:

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

这比使用非贪婪表达式更有效。

感谢 Daniel Vandersluis 让我想起了原子团!为了优化,它非常适合这里(如果必须回溯,此模式将永远无法匹配。)

我还加入了一个额外的[^&]+小组,以避免多次重复消极的​​前瞻性。

或者,可以使用所有格量词,它基本上做同样的事情(您的正则表达式引擎可能不支持它):

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

如您所见,它稍微短一些。

于 2009-07-17T13:46:07.010 回答