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

本文关键字:RegEx 替换 问题 URL 识别 相对于 帮助 | 更新日期: 2023-09-27 18:05:47

我一直在使用我在这里找到的一些代码来帮助我在HTML页面源中将相对url转换为绝对url。

我想用RegEx,而不是HTML敏捷包来解决这个问题。

我稍微修改了代码,它工作得很好,除了前面有"/"的相对URL被替换,但似乎,据我所知,不包括前面的斜杠的相对URL不是。

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

有没有人可以帮助我确定是什么原因导致这个不匹配我所描述的URL类型?

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;
    }

//Url转换

    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("~/", "/"));
    }

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

change

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

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

即去掉前面的斜杠

和在CSS部分更改

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

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

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

您可以更改ToAbsoluteUrl函数以返回给定属性的正确绝对URL。当表达式按照下面的建议进行更改时,ToAbsoluteUrl将接收没有前面~/的HTML属性,例如/path/a。而不是/~/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}"));

(我用m.Result代替了内部的Regex.Replace,这似乎是原作者的意图。)

两个重要的注意事项。首先,m.Groups("url")。值没有转义,所以像/path/${something}.aspx这样的源代码会抛出异常。(这个特性在原始代码中就有。)其次,一般不建议使用正则表达式来匹配HTML。例如,如果href="/path.asp"恰好出现在标记之外的源中,它将被匹配并转换。(您可以在模式的开头使用(?<'<[^>]*)这样的模式来防止这种情况,但是在<a onmouseover='"g(f(this)>2)'" href="/a.aspx">这样的情况下,由于>2,即使这样也会导致问题。)第三,这并没有解决CSS导入问题,尽管这个问题可以类似地解决(最简单的方法是将cssPattern中的''s*后面的/删除)。