Path.Combine для URL? - PullRequest
       144

Path.Combine для URL?

1134 голосов
/ 17 декабря 2008

Path.Combine удобен, но есть ли аналогичная функция в .NET Framework для URLs ?

Я ищу следующий синтаксис:

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

, который вернется:

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

Ответы [ 33 ]

12 голосов
/ 30 июля 2009

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

Одна рекомендация, Брайан: если вы заключите этот код в функцию, вы можете использовать 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");
}
8 голосов
/ 01 мая 2014

Объединение нескольких частей URL может быть немного сложнее. Вы можете использовать двухпараметрический конструктор Uri(baseUri, relativeUri) или служебную функцию Uri.TryCreate().

В любом случае вы можете в итоге вернуть неправильный результат, потому что эти методы продолжают обрезать относительные части первого параметра baseUri, то есть от примерно 1006 * до 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

7 голосов
/ 13 мая 2010

Простой способ объединить их и убедиться в их правильности:

string.Format("{0}/{1}", Url1.Trim('/'), Url2);
6 голосов
/ 22 мая 2013

Я обнаружил, UriBuilder очень хорошо сработало для такого рода вещей:

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

См. Класс UriBuilder - MSDN для получения дополнительных конструкторов и документации.

4 голосов
/ 01 ноября 2015

Вот метод Microsoft (OfficeDev PnP) 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

3 голосов
/ 17 мая 2015

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

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;
}
3 голосов
/ 21 июля 2016

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

    /// <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
3 голосов
/ 28 февраля 2017

Я считаю следующее полезным и имеет следующие функции:

  • Выбрасывает ноль или пробел
  • Принимает несколько параметров params для нескольких сегментов URL
  • бросает на ноль или пусто

Класс

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
2 голосов
/ 05 апреля 2016

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

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

  • Путь (каталог) должен заканчиваться на '/'. Если путь заканчивается без '/', последняя часть обрабатывается как имя файла и будет объединена при попытке объединить со следующей частью URL.
  • Есть одно исключение: базовый URL-адрес (без информации каталога) не должен заканчиваться на '/'
  • часть пути не должна начинаться с '/'. Если он начинается с '/', каждая существующая относительная информация из URL удаляется ... добавление пути детали string.Empty также удалит относительный каталог из 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();
        });
1 голос
/ 18 февраля 2014

Использование:

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

Он имеет то же поведение, что и Path.Combine.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...