4

我需要“盲目地”(即无法访问文件系统,在本例中为源代码控制服务器)将一些相对路径转换为绝对路径。所以我在玩点点和索引。对于那些好奇的人,我有一个由其他人的工具生成的日志文件,有时会输出相对路径,出于性能原因,我不想访问路径所在的源代码控制服务器以检查它们是否有效等等轻松地将它们转换为它们的绝对路径等价物。

我已经经历了许多(可能是愚蠢的)迭代试图让它工作 - 主要是迭代文件夹数组并尝试 delete_at(index) 和 delete_at(index-1) 但我的索引不断增加而我正在从自己下面删除数组的元素,这不适用于具有多个点的情况。任何有关改进它的技巧或特别是缺乏非连续点点支持的建议都将受到欢迎。

目前,这适用于我有限的示例,但我认为可以改进。它无法处理非连续的“..”目录,而且我可能正在做很多我可能不需要做的浪费(且容易出错)的事情,因为我有点笨拙。

我发现了很多使用其他语言转换其他类型的相对路径的示例,但它们似乎都不适合我的情况。

这些是我需要转换的示例路径,来自:

//depot/foo/../bar/single.c

//depot/foo/docs/../../other/double.c

//depot/foo/usr/bin/../../../else/more/triple.c

至:

//depot/bar/single.c

//depot/other/double.c

//depot/else/more/triple.c

还有我的脚本:

begin

paths = File.open(ARGV[0]).readlines

puts(paths)

new_paths = Array.new

paths.each { |path|
  folders = path.split('/')
  if ( folders.include?('..') )
    num_dotdots = 0
    first_dotdot = folders.index('..')
    last_dotdot = folders.rindex('..')
    folders.each { |item|
      if ( item == '..' )
        num_dotdots += 1
      end
    }
    if ( first_dotdot and ( num_dotdots > 0 ) ) # this might be redundant?
      folders.slice!(first_dotdot - num_dotdots..last_dotdot) # dependent on consecutive dotdots only
    end
  end

  folders.map! { |elem| 
    if ( elem !~ /\n/ )
      elem = elem + '/' 
    else
      elem = elem
    end
  }
  new_paths << folders.to_s

}

puts(new_paths)


end
4

3 回答 3

22

让我们不要重新发明轮子......File.expand_path为您做到这一点:

[
  '//depot/foo/../bar/single.c',
  '//depot/foo/docs/../../other/double.c',
  '//depot/foo/usr/bin/../../../else/more/triple.c'
].map {|p| File.expand_path(p) }
# ==> ["//depot/bar/single.c", "//depot/other/double.c", "//depot/else/more/triple.c"]
于 2010-05-14T19:59:13.193 回答
2

为什么不直接使用File.expand_path

irb(main):001:0> File.expand_path("//depot/foo/../bar/single.c")
=> "//depot/bar/single.c"
irb(main):002:0> File.expand_path("//depot/foo/docs/../../other/double.c")
=> "//depot/other/double.c"
irb(main):003:0> File.expand_path("//depot/foo/usr/bin/../../../else/more/triple.c")
=> "//depot/else/more/triple.c"

对于使用数组的 DIY 解决方案,我想到了这一点(也适用于您的示例):

absolute = []
relative = "//depot/foo/usr/bin/../../../else/more/triple.c".split('/')
relative.each { |d| if d == '..' then absolute.pop else absolute.push(d) end }
puts absolute.join('/')
于 2010-05-14T19:58:32.030 回答
1

Python代码:

paths = ['//depot/foo/../bar/single.c',
         '//depot/foo/docs/../../other/double.c',
         '//depot/foo/usr/bin/../../../else/more/triple.c']

def convert_path(path):
    result = []
    for item in path.split('/'):
        if item == '..':
            result.pop()
        else:
            result.append(item)
    return '/'.join(result)

for path in paths:
    print convert_path(path)

印刷:

//depot/bar/single.c
//depot/other/double.c
//depot/else/more/triple.c

您可以在 Ruby 中使用相同的算法。

于 2010-05-14T19:14:27.737 回答