代码之家  ›  专栏  ›  技术社区  ›  Brian MacKay

路径。合并URL?

  •  1489
  • Brian MacKay  · 技术社区  · 16 年前

    Path.Combine 很方便,但中有类似的功能吗。NET框架 URLs ?

    我正在寻找这样的语法:

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

    这将返回:

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

    42 回复  |  直到 10 年前
        1
  •  1322
  •   Karel Kral    6 年前

    Uri 有一个构造函数应该为你做这件事: new Uri(Uri baseUri, string relativeUri)

    这里有一个例子:

    Uri baseUri = new Uri("http://www.contoso.com");
    Uri myUri = new Uri(baseUri, "catalog/shownew.htm");
    

    编者注:注意,此方法不能按预期工作。在某些情况下,它可以切割baseUri的一部分。查看评论和其他答案。

        2
  •  220
  •   Matthew Sharpe    16 年前

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

    public static string Combine(string uri1, string uri2)
    {
        uri1 = uri1.TrimEnd('/');
        uri2 = uri2.TrimStart('/');
        return string.Format("{0}/{1}", uri1, uri2);
    }
    
        3
  •  181
  •   slugster Joey Cai    4 年前

    这里已经有了一些很好的答案。基于mdsharp的建议,这里有一个扩展方法,当你想处理Uri实例时可以很容易地使用:

    using System;
    using System.Linq;
    
    public static class UriExtensions
    {
        public static Uri Append(this Uri uri, params string[] paths)
        {
            return new Uri(paths.Aggregate(uri.AbsoluteUri, (current, path) => string.Format("{0}/{1}", current.TrimEnd('/'), path.TrimStart('/'))));
        }
    }
    

    使用示例:

    var url = new Uri("http://example.com/subpath/").Append("/part1/", "part2").AbsoluteUri;
    

    这将产生 http://example.com/subpath/part1/part2

    如果你想使用字符串而不是Uris,那么以下操作也会产生相同的结果,只需对其进行调整以满足你的需求:

    public string JoinUriSegments(string uri, params string[] segments)
    {
        if (string.IsNullOrWhiteSpace(uri))
            return null;
    
        if (segments == null || segments.Length == 0)
            return uri;
    
        return segments.Aggregate(uri, (current, segment) => $"{current.TrimEnd('/')}/{segment.TrimStart('/')}");
    }
    
    var uri = JoinUriSegements("http://example.com/subpath/", "/part1/", "part2");
    
        4
  •  156
  •   Ryan Cook    16 年前

    你使用 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

        5
  •  135
  •   mybrave Shamseer K    3 年前

    那里 is a Todd Menier's comment above Flurl 包括a Url.Combine .

    更多详情:

    Url。联合基本上是一条道路。合并URL,确保一个 部件之间只有一个分隔符:

    var url = Url.Combine(
        "http://MyUrl.com/",
        "/too/", "/many/", "/slashes/",
        "too", "few?",
        "x=1", "y=2"
    // result: "http://www.MyUrl.com/too/many/slashes/too/few?x=1&y=2" 
    

    得到 Flurl.Http on NuGet :

    PM>安装包装水槽。Http

    get the stand-alone URL builder 没有HTTP功能:

    PM>安装软件包Flurl

        6
  •  111
  •   Peter Mortensen icecrime    6 年前

    Ryan Cook的回答与我所追求的很接近,可能更适合其他开发人员。但是,它会在字符串的开头添加http://,通常它会比我想要的做更多的格式化。

    此外,对于我的用例,解析相对路径并不重要。

    mdsharp的答案也包含了一个好主意的种子,尽管实际的实现需要更多的细节才能完成。这是一种充实它的尝试(我在生产中使用了这个):

    C

    public string UrlCombine(string url1, string url2)
    {
        if (url1.Length == 0) {
            return url2;
        }
    
        if (url2.Length == 0) {
            return url1;
        }
    
        url1 = url1.TrimEnd('/', '\\');
        url2 = url2.TrimStart('/', '\\');
    
        return string.Format("{0}/{1}", url1, url2);
    }
    

    VB.NET语言

    Public Function UrlCombine(ByVal url1 As String, ByVal url2 As String) As String
        If url1.Length = 0 Then
            Return url2
        End If
    
        If url2.Length = 0 Then
            Return url1
        End If
    
        url1 = url1.TrimEnd("/"c, "\"c)
        url2 = url2.TrimStart("/"c, "\"c)
    
        Return String.Format("{0}/{1}", url1, url2)
    End Function
    

    此代码通过了以下测试,该测试恰好在VB中:

    <TestMethod()> Public Sub UrlCombineTest()
        Dim target As StringHelpers = New StringHelpers()
    
        Assert.IsTrue(target.UrlCombine("test1", "test2") = "test1/test2")
        Assert.IsTrue(target.UrlCombine("test1/", "test2") = "test1/test2")
        Assert.IsTrue(target.UrlCombine("test1", "/test2") = "test1/test2")
        Assert.IsTrue(target.UrlCombine("test1/", "/test2") = "test1/test2")
        Assert.IsTrue(target.UrlCombine("/test1/", "/test2/") = "/test1/test2/")
        Assert.IsTrue(target.UrlCombine("", "/test2/") = "/test2/")
        Assert.IsTrue(target.UrlCombine("/test1/", "") = "/test1/")
    End Sub
    
        7
  •  48
  •   PRMan Mike Fuchs    6 年前

    路径。Combine对我不起作用,因为QueryString参数中可能有像“|”这样的字符,因此URL也可能有,这将导致ArgumentException。

    我第一次尝试新的 Uri(Uri baseUri, string relativeUri) 这种方法对我来说失败了,因为URI像 http://www.mediawiki.org/wiki/Special:SpecialPages :

    new Uri(new Uri("http://www.mediawiki.org/wiki/"), "Special:SpecialPages")
    

    将导致Special:SpecialPages,因为结肠后 Special 这表示一个方案。

    因此,我最终不得不采用mdsharp/Brian MacKay的方法,并对其进行了进一步的开发,以处理多个URI部分:

    public static string CombineUri(params string[] uriParts)
    {
        string uri = string.Empty;
        if (uriParts != null && uriParts.Length > 0)
        {
            char[] trims = new char[] { '\\', '/' };
            uri = (uriParts[0] ?? string.Empty).TrimEnd(trims);
            for (int i = 1; i < uriParts.Length; i++)
            {
                uri = string.Format("{0}/{1}", uri.TrimEnd(trims), (uriParts[i] ?? string.Empty).TrimStart(trims));
            }
        }
        return uri;
    }
    

    用途: CombineUri("http://www.mediawiki.org/", "wiki", "Special:SpecialPages")

        8
  •  35
  •   Kolappan N t-clausen.dk    7 年前

    根据样品 URL 如果你提供了,我假设你想组合与你的网站相关的网址。

    基于这一假设,我将提出这个解决方案,作为对您问题的最恰当回应:“Path.Combine很方便,有没有 相似函数 在URL框架中?"

    既然有 相似函数 在URL框架中,我建议正确的方法是:“VirtualPathUtility.Combine”方法。 以下是MSDN参考链接: VirtualPathUtility.Combine Method

    有一个警告:我认为这只适用于与您的网站相关的URL(也就是说,您不能使用它来生成指向另一个网站的链接。例如, var url = VirtualPathUtility.Combine("www.google.com", "accounts/widgets"); ).

        9
  •  27
  •   JeremyWeir    14 年前
    Path.Combine("Http://MyUrl.com/", "/Images/Image.jpg").Replace("\\", "/")
    
        10
  •  18
  •   Peter Mortensen icecrime    6 年前

    我刚刚整理了一个小的扩展方法:

    public static string UriCombine (this string val, string append)
            {
                if (String.IsNullOrEmpty(val)) return append;
                if (String.IsNullOrEmpty(append)) return val;
                return val.TrimEnd('/') + "/" + append.TrimStart('/');
            }
    

    它可以这样使用:

    "www.example.com/".UriCombine("/images").UriCombine("first.jpeg");
    
        11
  •  16
  •   Peter Mortensen icecrime    6 年前

    将它们组合起来并确保其始终正确的一种简单方法是:

    string.Format("{0}/{1}", Url1.Trim('/'), Url2);
    
        12
  •  13
  •   Peter Mortensen icecrime    10 年前

    巧妙的例子,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");
    }
    
        13
  •  13
  •   GoldenAge    5 年前

    我认为这应该给你更大的灵活性,因为你可以处理任意多的路径段:

    public static string UrlCombine(this string baseUrl, params string[] segments)
    => string.Join("/", new[] { baseUrl.TrimEnd('/') }.Concat(segments.Select(s => s.Trim('/'))));
    
        14
  •  10
  •   Peter Mortensen icecrime    6 年前

    组合URL的多个部分可能有点棘手。您可以使用双参数构造函数 Uri(baseUri, relativeUri) ,或者您可以使用 Uri.TryCreate() 实用功能。

    在任何一种情况下,您最终都可能返回不正确的结果,因为这些方法不断截断第一个参数的相关部分 baseUri ,即来自类似的东西 http://google.com/some/thing http://google.com .

    为了能够将多个部分组合成一个最终的URL,您可以复制以下两个函数:

        public static string Combine(params string[] parts)
        {
            if (parts == null || parts.Length == 0) return string.Empty;
    
            var urlBuilder = new StringBuilder();
            foreach (var part in parts)
            {
                var tempUrl = tryCreateRelativeOrAbsolute(part);
                urlBuilder.Append(tempUrl);
            }
            return VirtualPathUtility.RemoveTrailingSlash(urlBuilder.ToString());
        }
    
        private static string tryCreateRelativeOrAbsolute(string s)
        {
            System.Uri uri;
            System.Uri.TryCreate(s, UriKind.RelativeOrAbsolute, out uri);
            string tempUrl = VirtualPathUtility.AppendTrailingSlash(uri.ToString());
            return tempUrl;
        }
    

    可以在以下网址找到带有单元测试的完整代码,以演示使用方法 https://uricombine.codeplex.com/SourceControl/latest#UriCombine/Uri.cs

    我有单元测试来涵盖三种最常见的情况:

    Enter image description here

        15
  •  10
  •   Peter Mortensen icecrime    6 年前

    我发现了 UriBuilder 这类事情做得很好:

    UriBuilder urlb = new UriBuilder("http", _serverAddress, _webPort, _filePath);
    Uri url = urlb.Uri;
    return url.AbsoluteUri;
    

    看见 UriBuilder Class - MSDN 了解更多构造函数和文档。

        16
  •  10
  •   Mahmoud Hanafy    5 年前

    正如在其他答案中发现的那样,要么是新的 Uri() TryCreate() 可以打勾。 但是,基本Uri必须以结尾 / 亲属不必以 / ;否则,它将删除基本Url的尾部

    我认为这最好作为一种扩展方法来实现,即。

    public static Uri Append(this Uri uri, string relativePath)
    {
        var baseUri = uri.AbsoluteUri.EndsWith('/') ? uri : new Uri(uri.AbsoluteUri + '/');
        var relative = relativePath.StartsWith('/') ? relativePath.Substring(1) : relativePath;
        return new Uri(baseUri, relative);
    }
    

    并使用它:

    var baseUri = new Uri("http://test.com/test/");
    var combinedUri =  baseUri.Append("/Do/Something");
    

    在性能方面,这消耗了比所需更多的资源,因为Uri类做了大量的解析和验证;一个非常粗略的分析(Debug)在大约2秒内完成了一百万次操作。 这适用于大多数场景,但是为了更高效,最好将所有内容都作为字符串进行操作,这需要125毫秒才能完成100万次操作。 也就是

    public static string Append(this Uri uri, string relativePath)
    {
        //avoid the use of Uri as it's not needed, and adds a bit of overhead.
        var absoluteUri = uri.AbsoluteUri; //a calculated property, better cache it
        var baseUri = absoluteUri.EndsWith('/') ? absoluteUri : absoluteUri + '/';
        var relative = relativePath.StartsWith('/') ? relativePath.Substring(1) : relativePath;
        return baseUri + relative;
    }
    

    如果你仍然想返回一个URI,那么100万次操作大约需要600毫秒。

    public static Uri AppendUri(this Uri uri, string relativePath)
    {
        //avoid the use of Uri as it's not needed, and adds a bit of overhead.
        var absoluteUri = uri.AbsoluteUri; //a calculated property, better cache it
        var baseUri = absoluteUri.EndsWith('/') ? absoluteUri : absoluteUri + '/';
        var relative = relativePath.StartsWith('/') ? relativePath.Substring(1) : relativePath;
        return new Uri(baseUri + relative);
    }
    

    我希望这能有所帮助。

        17
  •  6
  •   Tobias Schwarzinger    6 年前

    所以我有另一种方法,类似于所有使用UriBuilder的人。

    我不想拆分我的BaseUrl(它可以包含路径的一部分,例如。 http://mybaseurl.com/dev/ )as javajavajavajavajava 做。

    以下代码片段显示了代码+测试。

    小心: 此解决方案降低了主机的级别并附加了一个端口。如果不希望这样,可以通过例如利用 Uri 的财产 UriBuilder .

      public class Tests
      {
             public static string CombineUrl (string baseUrl, string path)
             {
               var uriBuilder = new UriBuilder (baseUrl);
               uriBuilder.Path = Path.Combine (uriBuilder.Path, path);
               return uriBuilder.ToString();
             }
    
             [TestCase("http://MyUrl.com/", "/Images/Image.jpg", "http://myurl.com:80/Images/Image.jpg")]
             [TestCase("http://MyUrl.com/basePath", "/Images/Image.jpg", "http://myurl.com:80/Images/Image.jpg")]
             [TestCase("http://MyUrl.com/basePath", "Images/Image.jpg", "http://myurl.com:80/basePath/Images/Image.jpg")]
             [TestCase("http://MyUrl.com/basePath/", "Images/Image.jpg", "http://myurl.com:80/basePath/Images/Image.jpg")]
             public void Test1 (string baseUrl, string path, string expected)
             {
               var result = CombineUrl (baseUrl, path);
    
               Assert.That (result, Is.EqualTo (expected));
             }
      }
    

    经过测试。NET Core 2.1在Windows 10上的运行。

    为什么这行得通?

    虽然 Path.Combine 将返回反斜杠(至少在Windows上),UriBuilder在Setter中处理这种情况 Path .

    取自 https://github.com/dotnet/corefx/blob/master/src/System.Private.Uri/src/System/UriBuilder.cs (注意电话 string.Replace )

    [AllowNull]
    public string Path
    {
          get
          {
              return _path;
          }
          set
          {
              if ((value == null) || (value.Length == 0))
              {
                  value = "/";
              }
              _path = Uri.InternalEscapeString(value.Replace('\\', '/'));
              _changed = true;
          }
     }
    

    这是最好的方法吗?

    当然,这个解决方案是相当自我描述的(至少在我看来)。但你依赖的是未记录的(至少我通过快速谷歌搜索没有发现任何东西)“功能”。NET API。这可能会随着未来的版本而改变,因此请涵盖测试方法。

    有测试 https://github.com/dotnet/corefx/blob/master/src/System.Private.Uri/tests/FunctionalTests/UriBuilderTests.cs ( Path_Get_Set )如果 \ 被正确地转换。

    旁注: 一个人也可以和 UriBuilder.Uri 如果uri将用于 System.Uri ctor。

        18
  •  6
  •   DubDub    6 年前

    对于那些正在寻找单行线并且只想连接路径的一部分而不创建新方法或引用新库或构造URI值并将其转换为字符串的人来说,那么。..

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

    这很基本,但我看不出你还需要什么。如果你害怕加倍的“/”,那么你可以简单地做一个 .Replace("//", "/") 之后。如果你害怕替换“https://”中的双引号“//”,那么请执行一次连接,替换双引号“/”,然后连接网站网址(但我很确定大多数浏览器会自动将前面有“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

        19
  •  6
  •   er sd    5 年前

    如果你不想有像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;
            });
        }
    
        20
  •  5
  •   TheGeneral    6 年前

    我发现以下内容很有用,并具有以下功能:

    • 在null或空白处抛出
    • 需要多个 params 多个Url段的参数
    • 抛出null或空

    public static class UrlPath
    {
       private static string InternalCombine(string source, string dest)
       {
          if (string.IsNullOrWhiteSpace(source))
             throw new ArgumentException("Cannot be null or white space", nameof(source));
    
          if (string.IsNullOrWhiteSpace(dest))
             throw new ArgumentException("Cannot be null or white space", nameof(dest));
    
          return $"{source.TrimEnd('/', '\\')}/{dest.TrimStart('/', '\\')}";
       }
    
       public static string Combine(string source, params string[] args) 
           => args.Aggregate(source, InternalCombine);
    }
    

    测验

    UrlPath.Combine("test1", "test2");
    UrlPath.Combine("test1//", "test2");
    UrlPath.Combine("test1", "/test2");
    
    // Result = test1/test2
    
    UrlPath.Combine(@"test1\/\/\/", @"\/\/\\\\\//test2", @"\/\/\\\\\//test3\") ;
    
    // Result = test1/test2/test3
    
    UrlPath.Combine("/test1/", "/test2/", null);
    UrlPath.Combine("", "/test2/");
    UrlPath.Combine("/test1/", null);
    
    // Throws an ArgumentException
    
        21
  •  5
  •   Dave Black    3 年前

    我有一个无分配的字符串创建版本,我一直在使用它并取得了巨大的成功。

    注:

    1. 对于第一个字符串:它使用以下命令修剪分隔符 TrimEnd(separator) -所以只能从字符串的末尾开始。
    2. 对于剩余部分:它使用以下方式修剪分离器 Trim(separator) -所以路径的开始和结束
    3. 它不附加尾随斜线/分隔符。虽然可以进行简单的修改来添加此功能。

    希望你觉得这有用!

    /// <summary>
    /// This implements an allocation-free string creation to construct the path.
    /// This uses 3.5x LESS memory and is 2x faster than some alternate methods (StringBuilder, interpolation, string.Concat, etc.).
    /// </summary>
    /// <param name="str"></param>
    /// <param name="paths"></param>
    /// <returns></returns>
    public static string ConcatPath(this string str, params string[] paths)
    {
        const char separator = '/';
        if (str == null) throw new ArgumentNullException(nameof(str));
    
        var list = new List<ReadOnlyMemory<char>>();
        var first = str.AsMemory().TrimEnd(separator);
    
        // get length for intial string after it's trimmed
        var length = first.Length;
        list.Add(first);
    
        foreach (var path in paths)
        {
            var newPath = path.AsMemory().Trim(separator);
            length += newPath.Length + 1;
            list.Add(newPath);
        }
    
        var newString = string.Create(length, list, (chars, state) =>
        {
            // NOTE: We don't access the 'list' variable in this delegate since 
            // it would cause a closure and allocation. Instead we access the state parameter.
    
            // track our position within the string data we are populating
            var position = 0;
    
            // copy the first string data to index 0 of the Span<char>
            state[0].Span.CopyTo(chars);
    
            // update the position to the new length
            position += state[0].Span.Length;
    
            // start at index 1 when slicing
            for (var i = 1; i < state.Count; i++)
            {
                // add a separator in the current position and increment position by 1
                chars[position++] = separator;
    
                // copy each path string to a slice at current position
                state[i].Span.CopyTo(chars.Slice(position));
    
                // update the position to the new length
                position += state[i].Length;
            }
        });
        return newString;
    }
    

    使用Benchmark DotNet输出:

    |                Method |     Mean |    Error |   StdDev |   Median | Ratio | RatioSD |  Gen 0 | Allocated |
    |---------------------- |---------:|---------:|---------:|---------:|------:|--------:|-------:|----------:|
    | ConcatPathWithBuilder | 404.1 ns | 27.35 ns | 78.48 ns | 380.3 ns |  1.00 |    0.00 | 0.3347 |   1,400 B |
    |            ConcatPath | 187.2 ns |  5.93 ns | 16.44 ns | 183.2 ns |  0.48 |    0.10 | 0.0956 |     400 B |
    
        22
  •  4
  •   Alex Titarenko    10 年前

    我的通用解决方案:

    public static string Combine(params string[] uriParts)
    {
        string uri = string.Empty;
        if (uriParts != null && uriParts.Any())
        {
            char[] trims = new char[] { '\\', '/' };
            uri = (uriParts[0] ?? string.Empty).TrimEnd(trims);
    
            for (int i = 1; i < uriParts.Length; i++)
            {
                uri = string.Format("{0}/{1}", uri.TrimEnd(trims), (uriParts[i] ?? string.Empty).TrimStart(trims));
            }
        }
    
        return uri;
    }
    
        23
  •  4
  •   Chris Marisic    8 年前

    这是微软的(OfficeDevPnP)方法 UrlUtility.Combine :

        const char PATH_DELIMITER = '/';
    
        /// <summary>
        /// Combines a path and a relative path.
        /// </summary>
        /// <param name="path"></param>
        /// <param name="relative"></param>
        /// <returns></returns>
        public static string Combine(string path, string relative) 
        {
            if(relative == null)
                relative = String.Empty;
    
            if(path == null)
                path = String.Empty;
    
            if(relative.Length == 0 && path.Length == 0)
                return String.Empty;
    
            if(relative.Length == 0)
                return path;
    
            if(path.Length == 0)
                return relative;
    
            path = path.Replace('\\', PATH_DELIMITER);
            relative = relative.Replace('\\', PATH_DELIMITER);
    
            return path.TrimEnd(PATH_DELIMITER) + PATH_DELIMITER + relative.TrimStart(PATH_DELIMITER);
        }
    

    来源: GitHub

        24
  •  4
  •   Neo    6 年前

    如果您不想添加第三方依赖项(如Flurl)或创建自定义扩展方法,请在ASP中。NET Core(也可在Microsoft.Owin中使用),您可以使用 PathString 其旨在建立URI路径。然后,您可以使用以下组合创建完整的URI, Uri UriBuilder .

    在这种情况下,它将是:

    new Uri(new UriBuilder("http", "MyUrl.com").Uri, new PathString("/Images").Add("/Image.jpg").ToString())
    

    这为您提供了所有组成部分,而无需在基本URL中指定分隔符。不幸的是, PathString 要求 / 被添加到每个字符串之前,否则它实际上会抛出一个 ArgumentException !但至少你可以以一种易于单元测试的方式确定地构建你的URI。

        25
  •  4
  •   user2368285    4 年前

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

    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")
    
        26
  •  3
  •   Nick N.    7 年前

    简单的一句话:

    public static string Combine(this string uri1, string uri2) => $"{uri1.TrimEnd('/')}/{uri2.TrimStart('/')}";
    

    灵感来自@Matt Sharpe的回答。

        27
  •  3
  •   Peter Mortensen icecrime    6 年前

    这是我的方法,我也会把它用于自己:

    public static string UrlCombine(string part1, string part2)
    {
        string newPart1 = string.Empty;
        string newPart2 = string.Empty;
        string seperator = "/";
    
        // If either part1 or part 2 is empty,
        // we don't need to combine with seperator
        if (string.IsNullOrEmpty(part1) || string.IsNullOrEmpty(part2))
        {
            seperator = string.Empty;
        }
    
        // If part1 is not empty,
        // remove '/' at last
        if (!string.IsNullOrEmpty(part1))
        {
            newPart1 = part1.TrimEnd('/');
        }
    
        // If part2 is not empty,
        // remove '/' at first
        if (!string.IsNullOrEmpty(part2))
        {
            newPart2 = part2.TrimStart('/');
        }
    
        // Now finally combine
        return string.Format("{0}{1}{2}", newPart1, seperator, newPart2);
    }
    
        28
  •  3
  •   Peter Mortensen icecrime    6 年前

    我创建了这个功能,可以让你的生活更轻松:

        /// <summary>
        /// The ultimate Path combiner of all time
        /// </summary>
        /// <param name="IsURL">
        /// true - if the paths are Internet URLs, false - if the paths are local URLs, this is very important as this will be used to decide which separator will be used.
        /// </param>
        /// <param name="IsRelative">Just adds the separator at the beginning</param>
        /// <param name="IsFixInternal">Fix the paths from within (by removing duplicate separators and correcting the separators)</param>
        /// <param name="parts">The paths to combine</param>
        /// <returns>the combined path</returns>
        public static string PathCombine(bool IsURL , bool IsRelative , bool IsFixInternal , params string[] parts)
        {
            if (parts == null || parts.Length == 0) return string.Empty;
            char separator = IsURL ? '/' : '\\';
    
            if (parts.Length == 1 && IsFixInternal)
            {
                string validsingle;
                if (IsURL)
                {
                    validsingle = parts[0].Replace('\\' , '/');
                }
                else
                {
                    validsingle = parts[0].Replace('/' , '\\');
                }
                validsingle = validsingle.Trim(separator);
                return (IsRelative ? separator.ToString() : string.Empty) + validsingle;
            }
    
            string final = parts
                .Aggregate
                (
                (string first , string second) =>
                {
                    string validfirst;
                    string validsecond;
                    if (IsURL)
                    {
                        validfirst = first.Replace('\\' , '/');
                        validsecond = second.Replace('\\' , '/');
                    }
                    else
                    {
                        validfirst = first.Replace('/' , '\\');
                        validsecond = second.Replace('/' , '\\');
                    }
                    var prefix = string.Empty;
                    if (IsFixInternal)
                    {
                        if (IsURL)
                        {
                            if (validfirst.Contains("://"))
                            {
                                var tofix = validfirst.Substring(validfirst.IndexOf("://") + 3);
                                prefix = validfirst.Replace(tofix , string.Empty).TrimStart(separator);
    
                                var tofixlist = tofix.Split(new[] { separator } , StringSplitOptions.RemoveEmptyEntries);
    
                                validfirst = separator + string.Join(separator.ToString() , tofixlist);
                            }
                            else
                            {
                                var firstlist = validfirst.Split(new[] { separator } , StringSplitOptions.RemoveEmptyEntries);
                                validfirst = string.Join(separator.ToString() , firstlist);
                            }
    
                            var secondlist = validsecond.Split(new[] { separator } , StringSplitOptions.RemoveEmptyEntries);
                            validsecond = string.Join(separator.ToString() , secondlist);
                        }
                        else
                        {
                            var firstlist = validfirst.Split(new[] { separator } , StringSplitOptions.RemoveEmptyEntries);
                            var secondlist = validsecond.Split(new[] { separator } , StringSplitOptions.RemoveEmptyEntries);
    
                            validfirst = string.Join(separator.ToString() , firstlist);
                            validsecond = string.Join(separator.ToString() , secondlist);
                        }
                    }
                    return prefix + validfirst.Trim(separator) + separator + validsecond.Trim(separator);
                }
                );
            return (IsRelative ? separator.ToString() : string.Empty) + final;
        }
    

    它适用于URL和普通路径。

    用途:

        // Fixes internal paths
        Console.WriteLine(PathCombine(true , true , true , @"\/\/folder 1\/\/\/\\/\folder2\///folder3\\/" , @"/\somefile.ext\/\//\"));
        // Result: /folder 1/folder2/folder3/somefile.ext
    
        // Doesn't fix internal paths
        Console.WriteLine(PathCombine(true , true , false , @"\/\/folder 1\/\/\/\\/\folder2\///folder3\\/" , @"/\somefile.ext\/\//\"));
        //result : /folder 1//////////folder2////folder3/somefile.ext
    
        // Don't worry about URL prefixes when fixing internal paths
        Console.WriteLine(PathCombine(true , false , true , @"/\/\/https:/\/\/\lul.com\/\/\/\\/\folder2\///folder3\\/" , @"/\somefile.ext\/\//\"));
        // Result: https://lul.com/folder2/folder3/somefile.ext
    
        Console.WriteLine(PathCombine(false , true , true , @"../../../\\..\...\./../somepath" , @"anotherpath"));
        // Result: \..\..\..\..\...\.\..\somepath\anotherpath
    
        29
  •  3
  •   Peter Mortensen icecrime    6 年前

    我发现 Uri 构造函数将“\”转换为“/”。所以你也可以使用 Path.Combine ,与 尤里 建设者。

     Uri baseUri = new Uri("http://MyUrl.com");
     string path = Path.Combine("Images", "Image.jpg");
     Uri myUri = new Uri(baseUri, path);
    
        30
  •  3
  •   Andreas    6 年前

    为什么不直接使用以下内容。

    System.IO.Path.Combine(rootUrl, subPath).Replace(@"\", "/")
    
    推荐文章