Path.Combine很方便,但是.NET框架中是否有类似的URL函数?

我正在寻找这样的语法:

Url.Combine("http://MyUrl.com/", "/Images/Image.jpg")

这将返回:

"http://MyUrl.com/Images/Image.jpg"


当前回答

//阅读以上所有示例,结果创建了我自己:

static string UrlCombine(params string[] items)
{
    if (items?.Any() != true)
    {
        return string.Empty;
    }

    return string.Join("/", items.Where(u => !string.IsNullOrWhiteSpace(u)).Select(u => u.Trim('/', '\\')));
}

//用法

UrlCombine("https://microsoft.com","en-us")

其他回答

您使用Uri.TryCreate(…):

Uri result = null;

if (Uri.TryCreate(new Uri("http://msdn.microsoft.com/en-us/library/"), "/en-us/library/system.uri.trycreate.aspx", out result))
{
    Console.WriteLine(result);
}

将返回:

http://msdn.microsoft.com/en-us/library/system.uri.trycreate.aspx

如果任何人正在寻找一个单行,并且只想在不创建新方法或引用新库的情况下连接路径的一部分,或者构造URI值并将其转换为字符串,那么。。。

string urlToImage = String.Join("/", "websiteUrl", "folder1", "folder2", "folder3", "item");

这很基本,但我看不出你还需要什么。如果你害怕“/”加倍,那么你可以简单地在后面做一个替换(“//”,“/”)。如果您害怕替换“https://”中的双引号“//”,那么请执行一次连接,替换双引号“/”,然后加入网站url(但是我很确定大多数浏览器会自动将前面带有“https://的内容转换为正确格式)。这看起来像:

string urlToImage = String.Join("/","websiteUrl", String.Join("/", "folder1", "folder2", "folder3", "item").Replace("//","/"));

这里有很多答案可以解决以上所有问题,但在我的情况下,我只需要在一个地方使用一次,不需要过度依赖它。此外,很容易看到这里发生了什么。

参见:https://learn.microsoft.com/en-us/dotnet/api/system.string.join?view=netframework-4.8

如果您不想拥有像Flurl这样的依赖项,可以使用它的源代码:

    /// <summary>
    /// Basically a Path.Combine for URLs. Ensures exactly one '/' separates each segment,
    /// and exactly on '&amp;' separates each query parameter.
    /// URL-encodes illegal characters but not reserved characters.
    /// </summary>
    /// <param name="parts">URL parts to combine.</param>
    public static string Combine(params string[] parts) {
        if (parts == null)
            throw new ArgumentNullException(nameof(parts));

        string result = "";
        bool inQuery = false, inFragment = false;

        string CombineEnsureSingleSeparator(string a, string b, char separator) {
            if (string.IsNullOrEmpty(a)) return b;
            if (string.IsNullOrEmpty(b)) return a;
            return a.TrimEnd(separator) + separator + b.TrimStart(separator);
        }

        foreach (var part in parts) {
            if (string.IsNullOrEmpty(part))
                continue;

            if (result.EndsWith("?") || part.StartsWith("?"))
                result = CombineEnsureSingleSeparator(result, part, '?');
            else if (result.EndsWith("#") || part.StartsWith("#"))
                result = CombineEnsureSingleSeparator(result, part, '#');
            else if (inFragment)
                result += part;
            else if (inQuery)
                result = CombineEnsureSingleSeparator(result, part, '&');
            else
                result = CombineEnsureSingleSeparator(result, part, '/');

            if (part.Contains("#")) {
                inQuery = false;
                inFragment = true;
            }
            else if (!inFragment && part.Contains("?")) {
                inQuery = true;
            }
        }
        return EncodeIllegalCharacters(result);
    }

    /// <summary>
    /// URL-encodes characters in a string that are neither reserved nor unreserved. Avoids encoding reserved characters such as '/' and '?'. Avoids encoding '%' if it begins a %-hex-hex sequence (i.e. avoids double-encoding).
    /// </summary>
    /// <param name="s">The string to encode.</param>
    /// <param name="encodeSpaceAsPlus">If true, spaces will be encoded as + signs. Otherwise, they'll be encoded as %20.</param>
    /// <returns>The encoded URL.</returns>
    public static string EncodeIllegalCharacters(string s, bool encodeSpaceAsPlus = false) {
        if (string.IsNullOrEmpty(s))
            return s;

        if (encodeSpaceAsPlus)
            s = s.Replace(" ", "+");

        // Uri.EscapeUriString mostly does what we want - encodes illegal characters only - but it has a quirk
        // in that % isn't illegal if it's the start of a %-encoded sequence https://stackoverflow.com/a/47636037/62600

        // no % characters, so avoid the regex overhead
        if (!s.Contains("%"))
            return Uri.EscapeUriString(s);

        // pick out all %-hex-hex matches and avoid double-encoding 
        return Regex.Replace(s, "(.*?)((%[0-9A-Fa-f]{2})|$)", c => {
            var a = c.Groups[1].Value; // group 1 is a sequence with no %-encoding - encode illegal characters
            var b = c.Groups[2].Value; // group 2 is a valid 3-character %-encoded sequence - leave it alone!
            return Uri.EscapeUriString(a) + b;
        });
    }

有趣的例子,Ryan,以函数的链接结尾。做得好。

一个建议Brian:如果您将此代码包装在函数中,则可能需要在TryCreate调用之前使用UriBuilder包装基URL。

否则,基本URL必须包含方案(其中UriBuilder将采用http://)。只是一个想法:

public string CombineUrl(string baseUrl, string relativeUrl) {
    UriBuilder baseUri = new UriBuilder(baseUrl);
    Uri newUri;

    if (Uri.TryCreate(baseUri.Uri, relativeUrl, out newUri))
        return newUri.ToString();
    else
        throw new ArgumentException("Unable to combine specified url values");
}

这可能是一个合适的简单解决方案:

public static string Combine(string uri1, string uri2)
{
    uri1 = uri1.TrimEnd('/');
    uri2 = uri2.TrimStart('/');
    return string.Format("{0}/{1}", uri1, uri2);
}