Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Simplify a relative URL

Tags:

c#

.net

I'm wondering if someone else can come up with a better way of simplifying relative URLs on either the basis of System.Uri or other means that are available in the standard .NET framework. My attempt works, but is pretty horrendous:

public static String SimplifyUrl(String url)
{
    var baseDummyUri = new Uri("http://example.com", UriKind.Absolute);
    var dummyUri = new Uri(baseDummyUri , String.Join("/",
        Enumerable.Range(0, url.Split(new[] { ".." }, StringSplitOptions.None).Length)
                  .Select(i => "x")));

    var absoluteResultUri = new Uri(dummyUri, url);
    var resultUri = dummyUri.MakeRelativeUri(absoluteResultUri);
    return resultUri.ToString();
}

This gives, for example:

./foo -> foo
foo/./bar -> foo/bar
foo/../bar -> bar

The problem that makes this so awkward is that Uri itself doesn't seem to simplify URLs that are relative and MakeRelativeUri also only works on absolute URLs. So to trick the Uri class into doing what I want, I construct a base URL that has the appropriate amount of nesting.

I could also use System.IO.Path, but then I'd have to search-and-replace backlashes to slashes...

There has to be a better way, right?

like image 312
John Avatar asked May 08 '16 00:05

John


1 Answers

You can do it with one-liner:

new Uri(new Uri("http://example.com/"), url).AbsolutePath.TrimStart('/');

The following test shows the results:

        [Theory]
        [InlineData("./foo", "foo")]
        [InlineData("/foo", "foo")]
        [InlineData("foo", "foo")]
        [InlineData("foo/./bar", "foo/bar")]
        [InlineData("/foo/./bar", "foo/bar")]
        [InlineData("/foo/../bar", "bar")]
        [InlineData("foo/../bar", "bar")]
        public void Test(string url, string expected)
        {
            var result = new Uri(new Uri("http://example.com/"), url).AbsolutePath.TrimStart('/');
            Assert.Equal(expected, result);
        }

Of course, if you want to leave / in the beginning just remove TrimStart('/')

like image 155
Piotr Stapp Avatar answered Sep 20 '22 21:09

Piotr Stapp