Путь.Объединить для URL-адресов?


путь.Комбайн удобно, но есть ли аналогичная функция в .NET framework для URLs?

Я ищу синтаксис такой:

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

что бы вернуться:

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

30 1049

30 ответов:

Uri имеет конструктор, который должен сделать это для вас: new Uri(Uri baseUri, string relativeUri)

вот пример:

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

вы используете 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

Это может быть достаточно простое решение:

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

здесь уже есть отличные ответы. Основываясь на предложении mdsharpe, вот метод расширения, который можно легко использовать, когда вы хотите иметь дело с экземплярами 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

этот вопрос получил некоторые большие, высоко проголосовали ответы!

ответ Райана Кука близок к тому, что мне нужно, и может быть более подходящим для других разработчиков. Тем не менее, он добавляет 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

на основе образца URL вы предоставили, я собираюсь предположить, что вы хотите объединить URL-адреса, которые относятся к вашему сайту.

исходя из этого я предлагаю это решение как наиболее подходящий ответ на ваш вопрос, который звучал так: "путь.Комбайн удобен, есть ли аналогичную функцию в рамках для URL?"

Так как там это аналогичную функцию в рамках для URL-адреса я предлагаю правильную формулировку: "виртуальность.Комбинированный метод. Вот ссылка на MSDN: VirtualPathUtility.Комбинировать Метод

есть одно предостережение: я считаю, что это работает только для URL-адресов относительно вашего сайта (то есть вы не можете использовать его для создания ссылок на другой веб-сайт. Например, var url = VirtualPathUtility.Combine("www.google.com", "accounts/widgets");).

путь.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, который обозначает схему.

так что мне, наконец, пришлось взять mdsharpe / Brian Mackays route и разработал его немного дальше для работы с несколькими частями uri:

public static string CombineUri(params string[] uriParts)
{
    string uri = string.Empty;
    if (uriParts != null && uriParts.Count() > 0)
    {
        char[] trims = new char[] { '\', '/' };
        uri = (uriParts[0] ?? string.Empty).TrimEnd(trims);
        for (int i = 1; i < uriParts.Count(); 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")

Path.Combine("Http://MyUrl.com/", "/Images/Image.jpg").Replace("\", "/")

Я просто собрал метод малого расширения

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");

остроумный пример, Райан, чтобы закончить ссылкой на функцию. Молодец.

одна рекомендация Брайан: если вы обернете этот код в функцию, вы можете использовать UriBuilder для обертывания базового URL-адреса до вызова TryCreate.

в противном случае базовый 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");
}

объединение нескольких частей URL-адреса может быть немного сложнее. Вы можете использовать конструктор 2 параметров Uri(baseUri, relativeUri), или вы можете использовать Uri.TryCreate() функции полезности. В любом случае, вы можете в конечном итоге вернуть неверный результат, потому что эти методы продолжают усекать относительные части от первого параметра baseUri, то есть от чего-то вроде http://google.com/some/thing до http://google.com

чтобы объединить несколько частей в окончательный url, вы можете скопировать 2 функции ниже:

    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

у меня есть модульные тесты для покрытия 3 наиболее распространенных случаев: enter image description here

этот ответ, вероятно, потерялся во всех ответах выше, но я нашел UriBuilder работал очень хорошо для такого рода вещи.

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

посмотреть UriBuilder Class-MSDN для большего количества конструкторов и документации.

Я знаю, что на это был дан ответ, но простой способ объединить их и убедиться, что это всегда правильно..

string.Format("{0}/{1}", Url1.Trim('/'), Url2);

вот Microsoft (OfficeDev PnP) метод UrlUtility.Комбайн:

    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

мое общее решение:

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

Я знаю, что я опоздал на вечеринку, но я создал эту функцию, которая сделает вашу жизнь проще

    /// <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

Я знаю, что этот вопрос хорошо ответил, однако я считаю это полезным, поскольку он имеет следующие особенности

  • сбрасывает на нуль или пробел
  • статический класс, который более точно имитирует System.Io.Path
  • принимает params параметр для нескольких сегментов Url

Примечание: Url-адрес имени класса может быть изменен, так как существует системный класс System.Security.Policy.Url

класс

public static class Url
{
   private static string InternalCombine(string source, string dest)
   {

      // If the source is null or white space retune the dest only
      if (string.IsNullOrWhiteSpace(source))
      {
         throw new ArgumentException("Cannot be null or white space", "source");
         // throw new ArgumentException("Cannot be null or white space", nameof(source)); // c# 6.0 Nameof Expression
      }

      if (string.IsNullOrWhiteSpace(dest))
      {
         throw new ArgumentException("Cannot be null or white space", "dest");
         // throw new ArgumentException("Cannot be null or white space", nameof(dest)); // c# 6.0 Nameof Expression
      }

      source =  source.TrimEnd('/', '\');
      dest = dest.TrimStart('/', '\');

      return string.Format("{0}/{1}", source, dest);
      // return $"{source}/{dest}"; // c# 6.0 string interpolation
   }

   public static string Combine(string source, params string[] args)
   {
      return args.Aggregate(source, InternalCombine);
   }
}

результаты

Url.Combine("test1", "test2");    
Url.Combine("test1//", "test2"); 
Url.Combine("test1", "/test2");

// Result = test1/test2

Url.Combine(@"test1\/\/\/", @"\/\/\\\//test2", @"\/\/\\\//test3\") ;

// Result = test1/test2/test3

Url.Combine("/test1/", "/test2/", null);
Url.Combine("", "/test2/");
Url.Combine("/test1/", null);

// Throws an ArgumentException

здесь Это комментарий Тодда Менье выше это Flurl включает в себя Url.Объединять.

Подробнее:

Url.Комбайн-это в основном путь.Объединить для URL-адресов, обеспечивая один и только один разделительный символ между частями:

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

Как насчет этого?

 public static class WebPath
    {
        public static string Combine(params string[] args)
        {
            var prefixAdjusted = args.Select(x => x.StartsWith("/") && !x.StartsWith("http") ? x.Substring(1) : x);
            return string.Join("/", prefixAdjusted);
        }
    }

вот мой подход, и я буду использовать его для себя тоже

public static string UrlCombine(string part1, string part2)
{
    string newPart1 = string.Empty;
    string newPart2 = string.Empty;
    string seprator = "/";

    // if either part1 or part 2 is empty,
    // we don't need to combine with seprator
    if (string.IsNullOrEmpty(part1) || string.IsNullOrEmpty(part2))
    {
        seprator = 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, seprator, newPart2);
}
    private Uri UriCombine(string path1, string path2, string path3 = "", string path4 = "")
    {
        string path = System.IO.Path.Combine(path1, path2.TrimStart('\', '/'), path3.TrimStart('\', '/'), path4.TrimStart('\', '/'));
        string url = path.Replace('\','/');
        return new Uri(url);
    }

имеет преимущества вести себя точно так же, как путь.Комбайн

правила при объединении URL с URI

чтобы избежать странного поведения есть одно правило, которому надо следовать:

  • путь (каталог) должен заканчиваться на '/'. если путь заканчивается без '/', последняя часть обрабатывается как имя файла, и она будет объединена при попытке объединить со следующей частью url.
  • есть 1 исключение: базовый URL-адрес (без информации о каталоге) не должен заканчиваться на'/'
  • часть пути не должна начинаться с'/', если она начните с ' / ' каждая существующая относительная информация из URL-адреса удаляется...добавление строки.Пустая часть пути будет удалить каталог из URL!

Если вы следуете правилам выше, вы можете комбинировать URL-адреса с кодом ниже. В зависимости от вашей ситуации, вы можете добавить несколько частей каталога в url...

        var pathParts = new string[] { destinationBaseUrl, destinationFolderUrl, fileName };

        var destination = pathParts.Aggregate((left, right) =>
        {
            if (string.IsNullOrWhiteSpace(right))
                return left;

            return new Uri(new Uri(left), right).ToString();
        });

почему бы просто не использовать следующие.

System.IO.Path.Combine(rootUrl, subPath).Replace(@"\", "/")

больше предложений... Я объединил все вышеперечисленное:

    public static string UrlPathCombine(string path1, string path2)
    {
        path1 = path1.TrimEnd('/') + "/";
        path2 = path2.TrimStart('/');

        return Path.Combine(path1, path2)
            .Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
    }

    [TestMethod]
    public void TestUrl()
    {
        const string P1 = "http://msdn.microsoft.com/slash/library//";
        Assert.AreEqual("http://msdn.microsoft.com/slash/library/site.aspx", UrlPathCombine(P1, "//site.aspx"));

        var path = UrlPathCombine("Http://MyUrl.com/", "Images/Image.jpg");

        Assert.AreEqual(
            "Http://MyUrl.com/Images/Image.jpg",
            path);
    }

Ну, я просто объединяю две строки и использую регулярные выражения для очистки части.

    public class UriTool
    {
        public static Uri Join(string path1, string path2)
        {
            string url = path1 + "/" + path2;
            url = Regex.Replace(url, "(?<!http:)/{2,}", "/");

            return new Uri(url);
        }
    }

Итак, вы можете использовать так:

    string path1 = "http://someaddress.com/something/";
    string path2 = "/another/address.html";
    Uri joinedUri = UriTool.Join(path1, path2);

    // joinedUri.ToString() returns "http://someaddress.com/something/another/address.html"

надеюсь, что это может быть полезным для кого-то!

я использовал этот код для решения проблемы:

string[] brokenBaseUrl = Context.Url.TrimEnd('/').Split('/');
string[] brokenRootFolderPath = RootFolderPath.Split('/');

for (int x = 0; x < brokenRootFolderPath.Length; x++)
{
    //if url doesn't already contain member, append it to the end of the string with / in front
    if (!brokenBaseUrl.Contains(brokenRootFolderPath[x]))
    {
        if (x == 0)
        {
            RootLocationUrl = Context.Url.TrimEnd('/');
        }
        else
        {
            RootLocationUrl += String.Format("/{0}", brokenRootFolderPath[x]);
        }
    }
}

обе эти работы

  Uri final = new Uri(Regex.Replace(baseUrl + "/" + relativePath, "(?<!http:)/{2,}", "/"));

или

  Uri final =new Uri(string.Format("{0}/{1}", baseUrl.ToString().TrimEnd('/'), relativePath.ToString().TrimStart('/')));

ie

Если

baseUrl ="http://tesrurl.test.com/Int18"

и

relativePath = "To_Folder"

выход = http://tesrurl.test.com/Int18/To_Folder

некоторые ошибки появятся для кода ниже

 // if you use below code, some issues will be there in final uri
 Uri final= new Uri(baseUrl ,relativePath );

просто один лайнер:

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

вдохновленный ответом @Matt Sharpe.

мы используем следующий простой вспомогательный метод для объединения произвольного количества частей URL вместе:

public static string JoinUrlParts(params string[] urlParts)
{
    return string.Join("/", urlParts.Where(up => !string.IsNullOrEmpty(up)).ToList().Select(up => up.Trim('/')).ToArray());
}

обратите внимание, что он не поддерживает '../../что-то/страница.htm ' - стиль относительный URL-s!

Я обнаружил, что конструктор Uri переворачивает ' \ 'в'/'. Таким образом, Вы также можете использовать путь.Комбинируйте, с Uri ctr.

 Uri baseUri = new Uri("http://MyUrl.com");
 string path = Path.Combine("Images","Image.jpg");
 Uri myUri = new Uri(baseUri , path);