URL에 대한 Path.Combine?


1243

Path.Combine 은 편리하지만 URL 의 .NET 프레임 워크에 비슷한 기능이 있습니까?

다음과 같은 구문을 찾고 있습니다.

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

이것은 다음을 반환합니다 :

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


14
Flurl 에는이를 수행하는 Url.Combine방법이 포함되어 있습니다 .
Todd Menier

2
실제로 //는 브라우저가 아닌 웹 사이트 또는 서버의 라우팅에 의해 처리됩니다. 주소 표시 줄에 넣은 내용을 보내드립니다. 그렇기 때문에 http : // 대신 htp : //를 입력하면 문제가 발생하기 때문에 //는 일부 사이트에서 큰 문제를 일으킬 수 있습니다. URL에 //가 있으면 404를 던지는 특정 웹 사이트를 처리하는 크롤러에 .dll을 작성하고 있습니다.
Dave Gordon

답변:


73

위의 토드 미니 어의 주석입니다 것을 Flurl가 포함이 Url.Combine.

자세한 내용은:

Url.Combine은 기본적으로 URL에 대한 Path.Combine으로, 파트 사이에 단 하나의 구분 문자를 보장합니다.

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" 

가져 NuGet에 Flurl.Http를 :

PM> 설치 패키지 Flurl.Http

또는 HTTP 기능없이 독립형 URL 빌더 를 확보하십시오.

PM> 설치 패키지 흐름


4
글쎄,이 질문은 많은 트래픽을 얻습니다 .1000 + upvotes의 대답은 실제로 모든 경우에 작동하지는 않습니다. 몇 년 후, 나는 실제로 이것을 위해 Flurl을 사용하므로 이것을 받아들입니다. 내가 만난 모든 경우에 효과가있는 것 같습니다. 사람들이 의존성을 원하지 않는다면, 나는 잘 작동하는 답변을 게시했습니다.
브라이언 맥케이

그리고 당신이 사용하지 않으면 Flurl 및 경량 버전, perfer 것 github.com/jean-lourenco/UrlCombine
lizzy91

1156

Uri 당신을 위해 이것을 해야하는 생성자가 있습니다 : new Uri(Uri baseUri, string relativeUri)

예를 들면 다음과 같습니다.

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

편집자 주 :이 방법은 예상대로 작동하지 않습니다. 경우에 따라 baseUri의 일부를자를 수 있습니다. 의견 및 기타 답변을 참조하십시오.


369
나는 Uri 클래스의 사용을 좋아하지만 불행히도 OP가 요청한 것처럼 Path.Combine처럼 작동하지 않습니다. 예를 들어 new Uri (new Uri ( " test.com/mydirectory/" ), "/helloworld.aspx"). ToString ()은 " test.com/helloworld.aspx "; Path.Combine 스타일 결과를 원한다면 올바르지 않습니다.
닥터 존스

195
모두 슬래시입니다. 상대 경로 부분이 슬래시로 시작하면 설명 된대로 동작합니다. 그러나 슬래시를 그대로두면 예상 한대로 작동합니다 (두 번째 매개 변수에서 누락 된 슬래시 참고). new Uri (new Uri ( " test.com/mydirectory/" ), "helloworld.aspx" ) .ToString ()은 " test.com/mydirectory/helloworld.aspx "가됩니다. Path.Combine도 비슷하게 동작합니다. 상대 경로 매개 변수가 슬래시로 시작하면 상대 경로 만 반환하고 결합하지 않습니다.
Joel Beckham

70
baseUri가 "test.com/mydirectory/mysubdirectory"인 경우 결과는 "test.com/mydirectory/mysubdirectory/helloworld.aspx"대신 "test.com/mydirectory/helloworld.aspx"가됩니다. 미묘한 차이는 첫 번째 매개 변수에 슬래시가 없다는 것입니다. 나는 기존 프레임 워크 방법을 사용하고 있습니다. 후미 슬래시가 이미 있어야하는 경우 partUrl1 + partUrl2를 수행하면 냄새가 훨씬 적습니다. 아마도 그 후행 슬래시를 쫓을 수 있었을 것입니다. 문자열 연결을하지 않기 위해.
Carl

63
URI 결합 방법을 원하는 유일한 이유는 후행 슬래시를 확인할 필요가 없기 때문입니다. 응용 프로그램이 루트에 있으면 Request.ApplicationPath는 '/'이고 그렇지 않으면 '/ foo'입니다.
nickd

24
나는 이것이 문제에 대한 답이 아니기 때문에이 대답에 -1을한다. Path.Combine을 사용하려는 경우와 같이 URL을 결합하려면 후행 /를 신경 쓰지 않습니다. 그리고 이것으로, 당신은 신경 써야합니다. 나는 위의 Brian MacKay 또는 mdsharpe의 솔루션을 선호합니다
Baptiste

160

이것은 매우 간단한 해결책 일 수 있습니다.

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

7
+1 : 상대 스타일 경로 (../../whatever.html)를 처리하지는 않지만 간단하기 때문에이 경로가 마음에 듭니다. 또한 '\'문자에 대한 트림을 추가합니다.
Brian MacKay

3
이 버전에 대한 자세한 내용은 내 답변을 참조하십시오.
Brian MacKay

149

당신은 사용 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


53
+1 : 출력 매개 변수에 비이성적 인 문제가 있지만 이것은 좋습니다. ;)
Brian MacKay

10
@Brian : 도움이되는 경우 모든 TryXXX 메소드 ( int.TryParse, DateTime.TryParseExact)에는 if 문에서 쉽게 사용할 수 있도록이 출력 매개 변수가 있습니다. Btw,이 예제에서 Ryan이했던 것처럼 변수를 초기화 할 필요는 없습니다.
Abel

41
이 답변은 같은 문제를 겪고 조엘의 : 결합을 test.com/mydirectory/하고 /helloworld.aspx있는됩니다 test.com/helloworld.aspx당신이 원하는 겉으로하지 않은.
매트 코카 지

3
안녕하세요, 다음에 실패했습니다 : if (Uri.TryCreate (new Uri ( " localhost / MyService /" ), "/ Event / SomeMethod? abc = 123", out result)) {Console.WriteLine (result); } 결과는 다음과 같습니다. localhost / Event / SomeMethod? abc = 123 참고 : 여기서 "http : //"는 기본 Uri에서 stackoverflow로 대체되었습니다.
Faisal Mq

3
@FaisalMq 루트에 상대적인 두 번째 매개 변수를 전달 했으므로 이는 올바른 동작입니다. 두 번째 매개 변수에서 선행 / 생략을 생략하면 예상 한 결과를 얻었을 것입니다.
Tom Lint

127

여기에 이미 훌륭한 답변이 있습니다. 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 를 생성 합니다


2
이 솔루션은 Path.Combine ()과 매우 유사한 UriUtils.Combine ( "base url", "part1", "part2", ...) 정적 메서드를 작성하는 것이 쉽지 않습니다. 좋은!
angularsen

상대 URI를 지원하려면 Uri 생성자에서 AbsoluteUri 및 UriKind.AbsoluteOrRelative 대신 ToString ()을 사용해야했습니다.
angularsen

상대 Uris에 대한 팁을 주셔서 감사합니다. 불행히도 Uri는 Request.ApplicationPath와 관련된 문제가 항상 있기 때문에 상대 경로를 쉽게 처리 할 수 ​​없습니다. 아마도 새로운 Uri (HttpContext.Current.Request.ApplicationPath)를 기본으로 사용하고 Append를 호출 할 수도 있습니까? 이렇게하면 절대 경로가 제공되지만 사이트 구조 내 어디에서나 작동해야합니다.
Ales Potocnik Hahonina

큰. 다른 사람에게 도움이되어 기쁘다. 지금까지 이것을 사용해 왔으며 아무런 문제가 없었습니다.
Ales Potocnik Hahonina

또한 추가 할 경로가 null 또는 빈 문자열이 아닌지 확인했습니다.
n.podbielski

91

Ryan Cook의 답변은 내가 추구하는 것에 가깝고 다른 개발자에게 더 적합 할 수 있습니다. 그러나 문자열의 시작 부분에 http : //를 추가하고 일반적으로 이전보다 조금 더 많은 형식을 지정합니다.

또한 사용 사례의 경우 상대 경로를 해결하는 것이 중요하지 않습니다.

mdsharp의 답변에는 좋은 아이디어의 씨앗도 포함되어 있지만 실제 구현에는 몇 가지 세부 사항이 더 필요했습니다. 이것은 그것을 육체 화하려는 시도입니다 (그리고 나는 이것을 프로덕션에서 사용하고 있습니다) :

씨#

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

4
세부 사항에 대한 이야기 ​​: ArgumentNullException("url1")논증이 의무적 인 경우에는 Nothing어떻습니까? 미안, 그냥 까다 롭고 ;-). 백 슬래시는 URI와 관련이 없으며 (있는 경우 트리밍해서는 안 됨) TrimXXX에서이를 제거 할 수 있습니다.
Abel

4
params string []을 사용하고 재귀 적으로 결합하여 둘 이상의 조합을 허용 할 수 있습니다.
Jaider

4
이것이 Path.Combine과 같은 기본 클래스 라이브러리에 있기를 바랍니다.
Uriah Blatherwick

1
@MarkHurd 코드를 다시 편집하여 C #과 동일하게 동작하며 구문 상 동일합니다.
JJS

1
@BrianMacKay 내가 그것을 깨뜨렸다, markhurd 내 실수를 지적하고 롤백, 다시 업데이트 ... 건배
JJS

36

"|"와 같은 문자가있을 수 있으므로 Path.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 경로를 가져 와서 여러 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")


1
+1 : 이제 이야기하고 있습니다 ... 시도해 보겠습니다. 이것은 심지어 받아 들여지는 새로운 대답이 될 수도 있습니다. 새로운 Uri () 메소드를 시도한 후 나는 그것을 정말로 좋아하지 않습니다. 너무 까다 롭습니다.
Brian MacKay

이것이 바로 내가 필요한 것입니다! 후행 슬래시 등을 어디에 두어야하는지 관심이없는 팬이 아니 었습니다.
Gromer

널 (null) 검사에서 롤링 할 때 +1이므로 폭파되지 않습니다.
NightOwl888

Count ()는 길이가 되어야만 라이브러리에 Linq를 포함시킬 필요가 없습니다.
PRMan

이것은 내가 찾던 것입니다.
ThePeter

34

제공 한 샘플 URL 을 기반으로 사이트와 관련된 URL을 결합한다고 가정하겠습니다.

이 가정을 바탕으로이 솔루션을 "Path.Combine이 편리 합니다. URL 프레임 워크에 비슷한 기능 이 있습니까?"

URL 프레임 워크에 비슷한 기능 이 있기 때문에 올바른 제안은 "VirtualPathUtility.Combine"입니다. MSDN 참조 링크는 다음과 같습니다. VirtualPathUtility.Combine 메서드

한 가지주의 사항이 있습니다.이 방법은 사이트와 관련된 URL에만 적용됩니다. 즉, 다른 웹 사이트에 대한 링크를 생성하는 데 사용할 수 없습니다 (예 :) var url = VirtualPathUtility.Combine("www.google.com", "accounts/widgets");.


내가 찾고있는 것과 가깝기 때문에 +1이지만 이전 URL에서 작동하면 이상적입니다. mdsharpe가 제안한 것보다 훨씬 우아해질 것입니다.
Brian MacKay

2
경고는 정확하고 절대 소변으로는 작동 할 수 없으며 결과는 항상 뿌리에서 상대적입니다. 그러나 "~ /"와 같이 물결표를 처리하는 이점도 있습니다. 이를 통해 바로 가기 Server.MapPath와 결합 할 수 있습니다.
Abel

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

12
path.Replace(Path.DirectorySeparatorChar, '/');
Jaider

5
path.Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)
SliverNinja-MSFT

1
/ Path.Combine ( "- 그것은 즉, 인수 초 / 첫 번째"/ 이미지 "제거해야합니다 U를 WRK에 도착 Http://MyUrl.com ", "이미지 / image.jpg를")
당 G

8
@SliverNinja 맞지 않음 이 필드의 값은 UNIX에서 백 슬래시 ( '\')이고 Windows 및 Macintosh 운영 체제에서 슬래시 ( '/')입니다. Linux 시스템에서 Mono를 사용할 때 잘못된 구분 기호가 표시됩니다.
user247702

6
디렉토리 분리기에서 괴로워하는 모든 사람들은 문자열이 현재와 다른 OS에서 나올 수 있다는 것을 잊고 있습니다. 백 슬래시를 슬래시로 바꾸면됩니다.
JeremyWeir

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

12

재치있는 예제 Ryan은 함수에 대한 링크로 끝납니다. 잘 했어.

한 가지 권장 사항 Brian :이 코드를 함수로 래핑하는 경우 UriBuilder를 사용하여 TryCreate 호출 전에 기본 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");
}

10

그것들을 결합하고 항상 올바른지 확인하는 쉬운 방법은 다음과 같습니다.

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

+1, 이것은 mdsharpe의 답변과 매우 유사하지만 내 답변에서 향상되었습니다. 이 버전은 Url2가 / 또는 \로 시작하거나 Url1이 실수로 \로 끝나거나 둘 중 하나가 비어 있지 않으면 효과적입니다! :)
Brian MacKay

9

URL의 여러 부분을 결합하는 것은 약간 까다로울 수 있습니다. 2- 파라미터 생성자 Uri(baseUri, relativeUri)를 사용하거나 Uri.TryCreate()유틸리티 함수를 사용할 수 있습니다 .

이러한 방법은 첫 번째 매개 변수의 떨어져 상대적인 부분을 잘라내는 계속 있기 때문에 각각의 경우에, 당신은 잘못된 결과를 반환 끝낼 수 있습니다 baseUri같은에서, 즉, http://google.com/some/thinghttp://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 에서 확인할 수 있습니다.

가장 일반적인 세 ​​가지 경우를 다루는 단위 테스트가 있습니다.

여기에 이미지 설명을 입력하십시오


2
나에게 꽤 좋아 보인다. 더 나은 명확성을 위해 I 루프를 foreach 루프로 바꿀 수는 있습니다.
Chris Marisic

고마워 크리스. Foreach를 사용하도록 코드를 변경했습니다.
Believe2014

1
모든 추가 노력에 +1. 나는 더 높은 투표 응답을 위해이 질문을 조금 유지해야합니다. 당신은 건틀릿을 버렸습니다. ;)
Brian MacKay

미안하지만 충분하지 않습니다. 당신이 보여주는 몇 가지 경우에서 작동하지만 al 조합으로 사용할 수는 없습니다. 예를 들어, 경로의 콜론은 해를 입힐 것입니다.
Gábor

무슨 뜻인지 예를 들어 주시겠습니까? 문제를 해결하고 다음 사용자를 도와 드리겠습니다.
Believe2014

7

나는 UriBuilder이런 종류의 일에 정말 효과적이라는 것을 알았 습니다.

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

더 많은 생성자와 문서는 UriBuilder 클래스-MSDN 을 참조하십시오 .


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


URL이 아닌 경로에 대한 것 같습니다.
Brian MacKay

@BrianMacKay 모양은 같지만 UrlUtility 클래스에서 가져 왔으며 URL 결합 컨텍스트에서 사용되었습니다.

2
어떤 클래스에 속하는지 명확히하기 위해 편집

이 클래스를 사용할 때주의하십시오. 나머지 클래스에는 SharePoint 관련 아티팩트가 포함되어 있습니다.
Harry Berry

4

다음이 유용하고 다음과 같은 기능이 있습니다.

  • 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

@PeterMortensen 편집 해 주셔서 감사합니다
TheGeneral

테스트와 관련된 몇 가지 문제 : // 4 번째 결과와 마지막 던지기 테스트의 결과 = test1 / test2 / test3 \ : ArgumentException 대신 ArgumentNullException을 발생시킵니다
Moriya

3

내 일반적인 해결책 :

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

나는 당신의 인생을 더 쉽게 만들어 줄이 기능을 만들었습니다 :

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

왜 다음을 사용하지 않습니까?

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

PowerShell 버전을 찾고 [System.IO.Path]::Combine("http://MyUrl.com/","/Images/Image.jpg")있었지만 다음과 같은 결과로 실패합니다 /Images/Image.jpg. /두 번째 하위 경로에서를 제거하면 작동합니다.[System.IO.Path]::Combine("http://MyUrl.com/","Images/Image.jpg")
Underverse

좋은 생각이지만 매개 변수 중 하나가 null이면 실패합니다.
pholpar

2

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

2

Flurl과 같은 타사 종속성을 추가하거나 ASP.NET Core (Microsoft.Owin에서도 사용 가능)에서 사용자 지정 확장 메서드를 만들지 않으려는 경우 PathStringURI를 구축 할 목적으로 사용할 수 있습니다. 경로. 그런 다음이의 조합을 사용하여 전체 URI를 만들 수 있습니다 UriUriBuilder.

이 경우 다음과 같습니다.

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

이를 통해 기본 URL에 구분 기호를 지정할 필요없이 모든 구성 요소가 제공됩니다. 불행하게도, PathString해야합니다 /그렇지 않으면 사실이를 throw 각 문자열 앞에 추가됩니다 ArgumentException! 그러나 최소한 단위 테스트가 쉬운 방식으로 URI를 결정 론적으로 작성할 수 있습니다.


2

UriBuilder를 사용한 모든 사람들과 비슷한 또 다른 접근 방식이 있습니다.

javajavajavajavajava처럼 경로의 일부를 포함 할 수있는 BaseUrl (예 : http://mybaseurl.com/dev/ )을 분할 하고 싶지 않았습니다.

다음 스 니펫은 코드 + 테스트를 보여줍니다.

주의 : 이 솔루션은 호스트를 소문자로 만들고 포트를 추가합니다. 이것이 바람직하지 않은 경우, 예를 들어의 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));
         }
  }

Windows 10에서 .NET Core 2.1로 테스트되었습니다.

왜 이것이 작동합니까?

Path.CombineWindows atleast에서 Backslashes를 반환 하더라도 UriBuilder는 Setter of에서이 경우를 처리합니다 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에서 문서화되지 않은 (적어도 빠른 Google 검색으로 아무것도 발견하지 못함) "기능"에 의존하고 있습니다. 추후 릴리스에서 변경 될 수 있으므로 테스트를 통해 분석법을 다루십시오.

https://github.com/dotnet/corefx/blob/master/src/System.Private.Uri/tests/FunctionalTests/UriBuilderTests.cs ( Path_Get_Set) 에는 테스트 \가 올바르게 변환되었는지 확인하는 테스트가 있습니다 .

사이드 참고 : 하나는 또한으로 일할 수있는 UriBuilder.Uri직접 속성의 URI가 사용됩니다 경우 System.Uri에 ctor.


이것은 매우 안정적인 접근 방식입니다. 단위 테스트를 위해 엄지 손가락!
aggsol

2

하나의 라이너를 찾고 새 메소드를 만들거나 새 라이브러리를 참조하지 않고 경로의 일부를 조인하거나 URI 값을 구성하여 문자열로 변환하려는 사람은 ...

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

꽤 기본적이지만 더 필요한 것이 무엇인지 알지 못합니다. '/'가 두 배가되는 것을 두려워하면 .Replace("//", "/")나중에 간단하게 수행 할 수 있습니다 . 'https : //'에서 두 배의 '//'를 바꾸는 것을 두려워하는 경우 한 번의 조인을 수행하고 두 번 '/'를 바꾼 다음 웹 사이트 URL에 참여하십시오 (그러나 대부분의 브라우저는 자동으로 올바른 형식으로 읽으려면 앞에 'https :'가있는 항목을 변환하십시오. 이것은 다음과 같습니다

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

여기에 위의 모든 것을 처리 할 수있는 많은 답변이 있지만 제 경우에는 한 위치에서 한 번만 필요했으며 크게 의존 할 필요가 없습니다. 또한 여기에서 무슨 일이 일어나고 있는지 쉽게 알 수 있습니다.

참조 : https://docs.microsoft.com/en-us/dotnet/api/system.string.join?view=netframework-4.8


1

사용하다:

    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있습니다.


1

여기 내 접근 방식이 있으며 나 자신도 사용할 것입니다.

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

이것은 귀하의 경우에만 허용됩니다. 코드가 손상 될 수있는 경우가 있습니다. 또한 경로의 일부를 올바르게 인코딩하지 않았습니다. 사이트 간 스크립팅 공격에있어 이것은 큰 취약점이 될 수 있습니다.
Believe2014

나는 당신의 요점에 동의합니다. 이 코드는 두 개의 URL 부분을 간단하게 결합해야합니다.
Bhagat Amit Bhagat

1

이것을 사용하십시오 :

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

'WebPath'를 잘 활용하십시오. :) 코드는 불필요하게 밀도가 높을 수 있습니다.이를 한 눈에보고 말하기가 어렵습니다. 그렇습니다. 완벽합니다. 단위 테스트를보고 싶습니다. 어쩌면 그건 나 뿐이야!
Brian MacKay

1
x.StartsWith ( "/") &&! x.StartsWith ( "http")-왜 http 확인? 무엇을 얻습니까?
penguat

http로 시작하는 경우 슬래시를 제거하지 않으려 고합니다.
Martin Murphy

@BrianMacKay, 두 개의 라이너가 단위 테스트를 보증하는지 확신 할 수 없지만 자유롭게 제공하려는 경우. 패치 나 다른 내용을 수락하는 것과 같지 않지만 제안을 자유롭게 편집하십시오.
Martin Murphy

1

Uri생성자가 '\'를 '/'로 뒤집는 것을 발견했습니다 . 따라서 생성자 Path.Combine와 함께을 사용할 수도 있습니다 Uri.

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

1

가치있는 것을 위해 여기에 몇 가지 확장 방법이 있습니다. 첫 번째는 경로를 결합하고 두 번째는 URL에 매개 변수를 추가합니다.

    public static string CombineUrl(this string root, string path, params string[] paths)
    {
        if (string.IsNullOrWhiteSpace(path))
        {
            return root;
        }

        Uri baseUri = new Uri(root);
        Uri combinedPaths = new Uri(baseUri, path);

        foreach (string extendedPath in paths)
        {
           combinedPaths = new Uri(combinedPaths, extendedPath);
        }

        return combinedPaths.AbsoluteUri;
    }

    public static string AddUrlParams(this string url, Dictionary<string, string> parameters)
    {
        if (parameters == null || !parameters.Keys.Any())
        {
            return url;
        }

        var tempUrl = new StringBuilder($"{url}?");
        int count = 0;

        foreach (KeyValuePair<string, string> parameter in parameters)
        {
            if (count > 0)
            {
                tempUrl.Append("&");
            }

            tempUrl.Append($"{WebUtility.UrlEncode(parameter.Key)}={WebUtility.UrlEncode(parameter.Value)}");
            count++;
        }

        return tempUrl.ToString();
    }

1

다른 답변에서 볼 수 있듯이 새로운 것이 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 클래스로 인해 필요한 것보다 더 많은 리소스를 소비합니다. 매우 거친 프로파일 링 (디버그)은 약 2 초 동안 백만 번의 작업을 수행했습니다. 이것은 대부분의 시나리오에서 작동하지만보다 효율적으로 모든 것을 문자열로 조작하는 것이 좋습니다 .1 백만 작업에 125 밀리 초가 걸립니다. 즉

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를 반환하려면 백만 개의 작업에 약 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);
}

이게 도움이 되길 바란다.


1

원하는만큼 많은 경로 세그먼트를 처리 할 수있는 유연성을 제공해야한다고 생각합니다.

public static string UrlCombine(this string baseUrl, params string[] segments)
=> string.Join("/", new[] { baseUrl.TrimEnd('/') }.Concat(segments.Select(s => s.Trim('/'))));
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.