2010-05-14 28 views
3

我需要「盲目地」(即不訪問文件系統,在這種情況下,源控制服務器)將一些相對路徑轉換爲絕對路徑。所以我在玩點數和指數。對於那些很好奇的我有一個由其他人的工具生成的日誌文件,有時會輸出相對路徑,出於性能原因,我不想訪問路徑所在的源代碼管理服務器來檢查它們是否有效,以及更多輕鬆地將它們轉換爲等價的絕對路徑。我經歷了一些(可能是愚蠢的)迭代試圖讓它工作 - 主要是迭代文件夾數組的一些變化,並試圖delete_at(index)和delete_at(index-1),但我的索引不斷增加,同時我從自己的下面刪除了數組的元素,這對於有多個點的情況並不適用。一般來說,改進它的任何提示,或者特別是缺乏非連續dotdot支持都是值得歡迎的。我可以做到這一點盲目相對於絕對路徑轉換(perforce倉庫路徑)更好嗎?

目前這是與我有限的例子,但我認爲它可以改善。它不能處理非連續的'..'目錄,而且我可能會做很多浪費(而且容易出錯)的東西,我可能不需要這樣做,因爲我有點破解。

我發現很多使用其他語言轉換其他類型的相對路徑的例子,但沒有一個似乎適合我的情況。

這些都是我需要轉換我的示例路徑,從:

//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 

回答

19

讓我們不要重新發明輪子.. 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"] 
+0

哇,我很驚訝,文件。expand_path沒有出現在谷歌搜索的許多變化之一的第一頁,我做了「紅寶石轉換相對於絕對路徑」。謝謝! – wonderfulthunk 2010-05-14 20:36:16

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

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