简化相对URL

时间:2016-05-08 00:40:38

标签: c# .net

我想知道其他人是否可以在System.Uri或标准.NET框架中提供的其他方法的基础上提出更好的简化相对URL的方法。我的尝试有效,但非常可怕:

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

这给出了例如:

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

使问题变得如此尴尬的问题是,Uri本身似乎并不简化相对的URL,MakeRelativeUri也只适用于绝对URL。因此,为了欺骗Uri类进行我想要的操作,我构建了一个具有适当嵌套量的基本URL。

我也可以使用System.IO.Path,但是我必须将反斜杠搜索和替换为斜线......

必须有更好的方法,对吧?

2 个答案:

答案 0 :(得分:10)

您可以使用单线来做到这一点:

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

以下测试显示了结果:

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

当然,如果您想一开始就离开/,只需删除TrimStart('/')

答案 1 :(得分:0)

这是一个解析问题。标记以“ /”分隔;令牌“ ..”减少了先前的令牌(如果有),而令牌“。”减少了是无人操作。

有一点曲折,是在用“ /”分隔字符串之后,我们需要跟踪它是绝对路径(以“ /”开始)还是相对路径(以“。”开始)。 )。如果缩小的路径为空,我们需要此方法。

public static class UrlHelper
{
    static public string Simplify(this string url)
    {
        string[] sourcePath = (url ?? "").Trim().Split('/');
        if (sourcePath.Count() == 0) { throw new ArgumentException(); }
        string startingAt = (sourcePath[0] == "")? "/": ".";

        Stack<string> simplifiedPath = new Stack<string>();
        foreach (string dir in sourcePath) {
            if (dir == ".") {
                continue;
            } else if (dir == ".." && simplifiedPath.Count > 0) {
                simplifiedPath.Pop();
                continue;
            }
            simplifiedPath.Push(dir);
        }
        string reducedPath = (simplifiedPath.Count == 0)? "": simplifiedPath.Reverse().Aggregate((path, dir) => path + "/" + dir);
        return (reducedPath == "") ? startingAt : reducedPath;
    }
}

一些测试:

    static void Main(string[] args)
    {
        Console.WriteLine("./foo".Simplify());         // => foo
        Console.WriteLine("foo/./bar".Simplify());     // => foo/bar
        Console.WriteLine("foo/../bar".Simplify());    // => bar
        Console.WriteLine("foo/bar/../..".Simplify()); // => .
        Console.WriteLine("/foo/bar/../..".Simplify()); // => /
        Console.WriteLine("../bar".Simplify());        // => ../bar
        Console.WriteLine("..".Simplify());            // => ..
        Console.WriteLine(".".Simplify());             // => .
        Console.WriteLine("/foo".Simplify());          // => /foo
        Console.WriteLine("/".Simplify());             // => /
        Console.ReadKey();
    }