帮助识别相对于绝对URL RegEx替换的问题

时间:2011-08-16 08:46:28

标签: c# regex

我一直在使用我发现here的一些代码来帮助我将相对URL转换为HTML页面源中的绝对URL。

我想使用RegEx,而不是针对此特定问题的HTML Agility包。

我已稍微修改了代码,除了替换了前面带有“/”的相对网址之外,它运行良好,但据我所知,似乎不包含前面斜杠的相对网址是不

我很确定问题出在初始的regEx字符串中,因为没有尝试替换。这超出了我的正规表达知识。

任何人都可以帮我确定导致这种情况不符合我所描述的网址类型的原因吗?

const string htmlPattern = "(?<attrib>\\shref|\\ssrc|\\sbackground)\\s*?=\\s*?" + "(?<delim1>[\"'\\\\]{0,2})(?!#|http|ftp|mailto|javascript)" + "/(?<url>[^\"'>\\\\]+)(?<delim2>[\"'\\\\]{0,2})";

//包装代码

public static string GetRelativePathReplacedHtml(string source, Uri uri)
    {
        source = source.HtmlAppRelativeUrlsToAbsoluteUrls( uri );

        return source;
    }

// RegEx匹配代码

public static string HtmlAppRelativeUrlsToAbsoluteUrls(this string html, Uri rootUrl)
    {
        if (string.IsNullOrEmpty(html))
            return html;

        const string htmlPattern = "(?<attrib>\\shref|\\ssrc|\\sbackground)\\s*?=\\s*?"
                                  + "(?<delim1>[\"'\\\\]{0,2})(?!#|http|ftp|mailto|javascript)"
                                  + "/(?<url>[^\"'>\\\\]+)(?<delim2>[\"'\\\\]{0,2})";

        var htmlRegex = new Regex(htmlPattern, RegexOptions.IgnoreCase | RegexOptions.Multiline);
        html = htmlRegex.Replace(html, m => htmlRegex.Replace(m.Value, "${attrib}=${delim1}" + ("~/" + m.Groups["url"].Value).ToAbsoluteUrl(rootUrl) + "${delim2}"));

        const string cssPattern = "@import\\s+?(url)*['\"(]{1,2}"
                                  + "(?!http)\\s*/(?<url>[^\"')]+)['\")]{1,2}";

        var cssRegex = new Regex(cssPattern, RegexOptions.IgnoreCase | RegexOptions.Multiline);
        html = cssRegex.Replace(html, m => cssRegex.Replace(m.Value, "@import url(" + ("~/" + m.Groups["url"].Value).ToAbsoluteUrl(rootUrl) + ")"));

        return html;
    }

//网址转换

    public static string ToAbsoluteUrl(this string relativeUrl, Uri rootUrl)
    {
        if (string.IsNullOrEmpty(relativeUrl))
            return relativeUrl;

        if (relativeUrl.StartsWith("/"))
            relativeUrl = relativeUrl.Insert(0, "~");
        if (!relativeUrl.StartsWith("~/"))
            relativeUrl = relativeUrl.Insert(0, "~/");

        var url = rootUrl;
        var port = url.Port != 80 ? (":" + url.Port) : String.Empty;

        // return string.Format("{0}://{1}{2}{3}", url.Scheme, url.Host, port, VirtualPathUtility.ToAbsolute(relativeUrl));
        return string.Format("{0}://{1}{2}{3}", url.Scheme, url.Host, port, relativeUrl.Replace("~/", "/"));
    }

2 个答案:

答案 0 :(得分:1)

更改

+ "/(?<url>[^\"'>\\\\]+)(?<delim2>[\"'\\\\]{0,2})";  

+ "(?<url>[^\"'>\\\\]+)(?<delim2>[\"'\\\\]{0,2})";  

即删除前导斜杠

并在css部分更改

+ "(?!http)\\s*/(?<url>[^\"')]+)['\")]{1,2}";  

+ "(?!http)\\s*(?<url>[^\"')]+)['\")]{1,2}";  

答案 1 :(得分:1)

我怀疑问题只是部分正则表达式,它要求相对URL以开头“/”开头。删除此限制仍然会失败,因为ToAbsoluteUrl方法最终会调用VirtualPathUtility.ToAbsolute,这需要一个带根的URL(相对于应用程序或绝对值)。

您可以更改ToAbsoluteUrl函数以返回给定属性的正确绝对URL。 当表达式如下所述更改时,ToAbsoluteUrl将接收不带前面的〜/的HTML属性,例如/path/a.aspx而不是/〜/ path / a.aspx。。然后可以将模式放宽到:

const string htmlPattern =  @"(?<attrib>\s(?>href|src|background))\s*=\s*"
                 + @"(?<delim1>[""'\\])(?!#|(?>https?|ftp|mailto|javascript|file)://)"
                 + @"(?<url>.+?)\k<delim1>";
                 // to handle escaped deliminators in URL string, use below
                 // in place of last segment:
                 // + @"(?<url>.+?)(?<!(?:(?<!\\)(?:\\\\)*)\\)\k<delim1>";

后两行:

html = htmlRegex.Replace(html, m => m.Result("${attrib}=${delim1}"
       + (m.Groups["url"].Value).ToAbsoluteUrl(rootUrl)
       + "${delim2}"));

(我将内部Regex.Replace替换为m.Result,这似乎是原作者的意图。)

两个重要的注释。首先,m.Groups [“url”]。值不会被转义,因此像/path/${something}.aspx这样的来源会引发异常。 (这个特征出现在原始代码中。)其次,the general caveat that using regular expressions to match HTML is generally not advised。例如,如果href="/path.asp"恰好出现在 标记的源中,则会匹配并转换它。 (您可以在模式的开头使用类似(?<\<[^>]*)的模式来防范这种情况,但即使这样也会因<a onmouseover=\"g(f(this)>2)\" href="/a.aspx">而导致>2等问题。)第三,这个不会解决CSS导入问题,但可以类似地解决(最简单的方法是删除/\\s*之后的cssPattern)。