Vb.net 使用未知父引用规范化路径 问题陈述

Vb.net 使用未知父引用规范化路径 问题陈述,vb.net,path,normalization,Vb.net,Path,Normalization,我当前的项目需要处理许多unix风格的路径,最重要的是连接路径和规范化路径 通过规范化,我的意思是删除对当前目录()的所有引用、对父目录(。)的引用和冗余的前斜杠(/),同时保留原始路径的“含义” 例如:路径/foo/bar和/foo//bar和/foo/baz//bar都指向同一目录。然而,进行简单的字符串比较显然表明它们是不同的路径。这就是为什么我试图规范化路径,以便它们都被同等对待 这样做的代码实际上并不难写。你可以在问题的底部找到我的代码。但还有一个问题,我有麻烦 目前,用户可以输入如下

我当前的项目需要处理许多unix风格的路径,最重要的是连接路径和规范化路径

通过规范化,我的意思是删除对当前目录(
)的所有引用、对父目录(
)的引用和冗余的前斜杠(
/
),同时保留原始路径的“含义”

例如:路径
/foo/bar
/foo//bar
/foo/baz//bar
都指向同一目录。然而,进行简单的字符串比较显然表明它们是不同的路径。这就是为什么我试图规范化路径,以便它们都被同等对待

这样做的代码实际上并不难写。你可以在问题的底部找到我的代码。但还有一个问题,我有麻烦

目前,用户可以输入如下所示的路径:

input:      /../../../foo/bar
normalized: /foo/bar
因为这是一个绝对路径,所以它正确解析为根目录(
/
)中的
foo/bar

然而,当输入是一个相对路径时,我不可能回溯所需的步骤数量,因为我不知道父目录的名称

input:      ../../../foo/bar
normalized: foo/bar
假设完整路径是
/a/b/c/d/../../../../../foo/bar
,在这种情况下,算法生成:

input:      /a/b/c/d/../../../foo/bar
normalized: /a/foo/bar
无论出于何种原因,当路径被拆分为
/a/b/c/d
。/../../../foo/bar
时,就会出现问题

input:      /a/b/c/d/
input:      ../../../foo/bar
normalized: /a/b/c/d
normalized: foo/bar

joined: /a/b/c/d/foo/bar
如您所见,当规范化输出值重新连接在一起时,路径已失去其原始含义。如果我没有删除前导父引用,就不会发生这种情况

所以我想我有3个选项,在相对路径未知父引用的情况下:

  • 删除前导父引用,即使结果在技术上是错误的
  • 保留前导父引用,即使结果在技术上没有规范化
  • 出错
  • 我希望一些天才能想出一个更好的主意。但如果不是,你会怎么做

    代码 我还没有针对每个可能的用例测试我的代码,但它应该是相对(双关语)稳定的

    Public MustInherit类UnixPath
    私人分新
    端接头
    ''' 
    ''获取指定的路径是否为绝对路径。
    ''' 
    公共共享函数IsAbsolute(路径为字符串)为布尔值
    返回path.StartsWith(UnixPath.Separator、StringComparison.InvariantCulture)
    端函数
    ''' 
    ''规范化字符串路径,考虑'..'和'.'部分。
    ''' 
    公共共享函数规范化(路径为字符串)为字符串
    如果String.IsNullOrEmpty(路径),则
    返回字符串。空
    如果结束
    Dim oldPath=path.Split(New Char(){UnixPath.Separator},StringSplitOptions.RemoveEmptyEntries)
    将新路径调整为新堆栈(字符串的)
    Dim skipCount As Integer=0
    对于i=oldPath.GetUpperBound(0)到oldPath.GetLowerBound(0)步骤-1
    如果String.Equals(oldPath(i)、UnixPath.CurrentDirectory、StringComparison.InvariantCulture),则
    继续
    ElseIf String.Equals(oldPath(i)、UnixPath.ParentDirectory、StringComparison.InvariantCulture)然后
    skipCount+=1
    如果skipCount>0,则
    skipCount-=1
    其他的
    newPath.Push(旧路径(i))
    如果结束
    下一个
    如果使用UnixPath.IsAbsolute(路径),则
    返回UnixPath.Join(UnixPath.Separator,UnixPath.Join(newPath.ToArray))
    其他的
    对于i=1,进行skipCount
    Push(UnixPath.ParentDirectory)
    下一个
    返回UnixPath.Join(newPath.ToArray)
    如果结束
    端函数
    ''' 
    ''组合了一个字符串路径数组。
    ''' 
    公共共享函数联接(参数数组路径为String())为String
    Dim builder作为新的StringBuilder
    Dim count=路径。GetUpperBound(0)
    对于i=path.GetLowerBound(0)进行计数
    如果String.IsNullOrEmpty(路径(i))那么
    继续
    如果结束
    Append(路径(i).TrimEnd(UnixPath.Separator))
    如果我=计数,那么
    退出
    如果结束
    Append(UnixPath.Separator)
    下一个
    Return builder.ToString
    端函数
    公共共享只读属性CurrentDirectory作为字符串
    得到
    返回”
    结束
    端属性
    公共共享只读属性ParentDirectory作为字符串
    得到
    返回“.”
    结束
    端属性
    公共共享只读属性分隔符作为字符
    得到
    返回“/”c
    结束
    端属性
    末级
    
    删除
    不会保留原始路径的意义。
    ,只能删除重复的
    /
    。不过,你想做什么还不清楚。可能你真的不需要这样“规范化”你的路径

    无论如何,这里有一个想法:

    Dim inputPath As String = "/../../../foo/bar"
    Dim outputPath As String = inputPath.Replace(".", "").Replace("..", "")
    Dim outputPathLength As Integer
    Do
      outputPathLength = outputPath.Length
      outputPath = outputPath.Replace("//", "/")
    Loop Until outputPathLength = outputPath.Length
    
    为了获得更好的实现(这也可以解释您的案例2,以及更多),您可能应该使用正则表达式

    编辑:有些人可能会认为这是黑客行为,但这里有另一种选择:

    Dim inputPath As String = "../../../foo/bar"
    Dim outPath As String = IO.Path.GetFullPath(IO.Path.Combine("C:\", inputPath))
    Dim newPath As String = outPath.Substring(outPath.IndexOf("\") + 1).Replace("\", "/")
    If inputPath.StartsWith("/") Then newPath = "/" & newPath
    MsgBox(newPath)
    

    它使用文件系统规范化路径,并转换回unix样式。适用于上述所有测试用例。

    顺便说一句,如果无法确定前导父引用的名称,我倾向于将它们放回原位。赞成还是反对?有人吗?你好!我在我的问题陈述中添加了一个例子,以更好地解释我正在尝试做什么。我附加的代码非常完整,尽管我希望看到一个使用正则表达式的工作替代方案
    Dim inputPath As String = "../../../foo/bar"
    Dim outPath As String = IO.Path.GetFullPath(IO.Path.Combine("C:\", inputPath))
    Dim newPath As String = outPath.Substring(outPath.IndexOf("\") + 1).Replace("\", "/")
    If inputPath.StartsWith("/") Then newPath = "/" & newPath
    MsgBox(newPath)