【问题标题】:Could I do this blind relative to absolute path conversion (for perforce depot paths) better?我可以相对于绝对路径转换(对于 perforce 仓库路径)更好地做到这一点吗?
【发布时间】:2010-05-14 18:59:00
【问题描述】:

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

我已经经历了许多(可能是愚蠢的)迭代试图让它工作 - 主要是迭代文件夹数组并尝试 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

【问题讨论】:

    标签: ruby algorithm relative-path absolute-path


    【解决方案1】:

    我们不要重新发明轮子...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"]
    

    【讨论】:

    • 哇,我很惊讶 File.expand_path 没有出现在我为“ruby 相对于绝对路径转换”所做的许多谷歌搜索变体之一的第一页上。谢谢!
    【解决方案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('/')
    

    【讨论】:

      【解决方案3】:

      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 中使用相同的算法。

      【讨论】:

        猜你喜欢
        • 2019-11-14
        • 1970-01-01
        • 1970-01-01
        • 2017-08-01
        • 2011-11-07
        • 2011-05-02
        相关资源
        最近更新 更多