1394

Path.Combineは便利ですが、URL用の .NET フレームワークに同様の機能はありますか?

次のような構文を探しています。

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

これは次を返します:

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

4

42 に答える 42

1270

Uriあなたのためにこれを行うべきコンストラクタがあります:new Uri(Uri baseUri, string relativeUri)

次に例を示します。

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

編集者からの注記: 注意してください。この方法は期待どおりに機能しません。場合によっては、baseUri の一部を切り取ることができます。コメントとその他の回答を参照してください。

于 2009-10-06T19:37:12.203 に答える
195

これは適切に単純な解決策かもしれません:

public static string Combine(string uri1, string uri2)
{
    uri1 = uri1.TrimEnd('/');
    uri2 = uri2.TrimStart('/');
    return string.Format("{0}/{1}", uri1, uri2);
}
于 2009-09-25T10:29:57.050 に答える
157

ここにはすでにいくつかの素晴らしい答えがあります。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が生成されます

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");
于 2011-11-03T10:20:37.333 に答える
153

あなたが使用する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

于 2008-12-16T21:49:56.253 に答える
102

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
于 2010-05-10T21:53:04.547 に答える
34

提供されたサンプルURLに基づいて、サイトに関連する URL を組み合わせる必要があると想定します。

この仮定に基づいて、「Path.Combine は便利ですが、URL のフレームワークに同様の機能はありますか?」という質問に対する最も適切な回答として、このソリューションを提案します。

URL のフレームワークには同様の機能があるため、正しいのは「VirtualPathUtility.Combine」メソッドです。MSDN リファレンス リンクは次のとおりです: VirtualPathUtility.Combine メソッド

注意点が 1 つあります。これは、サイトに関連する URL に対してのみ機能すると思います (つまり、別の Web サイトへのリンクを生成するために使用することはできません。たとえば、var url = VirtualPathUtility.Combine("www.google.com", "accounts/widgets");)。

于 2010-03-28T00:21:37.617 に答える
25
Path.Combine("Http://MyUrl.com/", "/Images/Image.jpg").Replace("\\", "/")
于 2011-01-11T21:41:18.130 に答える
17

小さな拡張メソッドをまとめました:

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");
于 2010-11-25T08:43:19.760 に答える
13

機知に富んだ例、ライアン、関数へのリンクで締めくくります。素晴らしい。

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");
}
于 2009-07-30T15:08:28.870 に答える
12

それらを組み合わせて常に正しいことを確認する簡単な方法は次のとおりです。

string.Format("{0}/{1}", Url1.Trim('/'), Url2);
于 2010-05-12T21:42:32.000 に答える
10

URL の複数の部分を組み合わせるのは少し難しいかもしれません。2 パラメーターのコンストラクターを使用するか、ユーティリティ関数Uri(baseUri, relativeUri)を使用できます。Uri.TryCreate()

どちらの場合でも、これらのメソッドは最初のパラメータから相対的な部分を切り捨て続けるためbaseUri、つまりhttp://google.com/some/thingtoのようなものから、間違った結果を返すことになる可能性があります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 つのケースをカバーする単体テストがあります。

ここに画像の説明を入力してください

于 2014-04-30T22:21:05.780 に答える
8

UriBuilderはこの種のことのために本当にうまくいったことを発見しました:

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

その他のコンストラクターとドキュメントについては、 「 UriBuilder クラス - MSDN」を参照してください。

于 2013-05-22T12:19:12.343 に答える
6

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;
        });
    }
于 2020-06-20T10:15:12.680 に答える
4

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

于 2015-11-01T18:34:51.633 に答える
4

私の一般的な解決策:

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;
}
于 2015-05-17T07:52:20.983 に答える
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);
    }
}
于 2012-12-10T15:31:30.493 に答える
2

URL と URI を組み合わせる際のルール

奇妙な動作を避けるために、従うべきルールが 1 つあります。

  • パス (ディレクトリ) は「/」で終わる必要があります。パスが「/」なしで終わる場合、最後の部分はファイル名のように扱われ、次の URL 部分と結合しようとすると連結されます。
  • 例外が 1 つあります。ベース 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();
        });
于 2016-04-05T05:04:15.623 に答える
2

これが私のアプローチであり、私自身にも使用します。

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);
}
于 2013-08-03T03:39:54.637 に答える
2

// 上記のすべてのサンプルを読み取り、結果として自分自身を作成し​​ました:

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")
于 2021-04-02T05:23:56.640 に答える
0

このコードを使用して問題を解決しました。

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]);
        }
    }
}
于 2015-12-03T23:17:16.043 に答える
0

以前のすべての回答を組み合わせました。

    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);
    }
于 2013-04-25T10:51:01.590 に答える
0

2 つの文字列を連結し、正規表現を使用してクリーニング部分を実行するだけです。

    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"
于 2014-05-15T23:49:12.660 に答える
-2

次のコードはまだ使用していませんが、インターネット旅行中に URL 結合の問題を解決するために見つけました - 簡潔な (そして成功した!) 答えであることを願っています:

VirtualPathUtility.Combine
于 2013-02-28T03:40:03.857 に答える
-2

Path.Combine少なくとも.NET 4では、これも直接機能するように見えることを指摘しなければなりません。

于 2010-07-01T16:02:14.943 に答える