【问题标题】:Simplify a relative URL简化相对 URL
【发布时间】:2016-09-02 20:47:40
【问题描述】:

我想知道其他人是否可以根据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,但我必须搜索并将反斜杠替换为斜杠...

一定有更好的方法,对吧?

【问题讨论】:

  • 你能举例说明你的意思吗?您要简化的 url 是什么,简化后的 url 是什么?
  • @ScottHannen 添加了示例。
  • 我认为您的解决方案很棒。这可能是进行替换的最简单方法。

标签: c# .net


【解决方案1】:

你可以用单线做到这一点:

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('/')

【讨论】:

    【解决方案2】:

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

    有一点点变化,就是在我们用“/”分隔字符串之后,我们需要跟踪它是绝对路径(从“/”开始)还是相对路径(从“.”开始) )。我们需要这个以防减少的路径为空。

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

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-26
    • 2013-10-16
    • 1970-01-01
    • 1970-01-01
    • 2013-03-12
    • 1970-01-01
    相关资源
    最近更新 更多