2010-05-14 2 views
3

Мне нужно «слепо» (т. Е. Без доступа к файловой системе, в этом случае серверу управления версиями) конвертировать некоторые относительные пути в абсолютные пути. Поэтому я играю с точками и индексами. Для любопытных у меня есть файл журнала, созданный чужим инструментом, который иногда выводит относительные пути, а по соображениям производительности я не хочу обращаться к серверу управления версиями, где расположены пути, чтобы проверить, действительны ли они и легко преобразовать их в их эквиваленты абсолютного пути.Могу ли я сделать это слепое относительно абсолютного пути преобразования (для perforce пути депо) лучше?

Я прошел через несколько (возможно, глупых) итераций, пытаясь заставить его работать - в основном несколько вариантов итерации по массиву папок и попытки delete_at (index) и delete_at (index-1), но мой индекс продолжал увеличиваться, в то время как я удалял элементы массива из-под себя, что не работало для случаев с несколькими точками. Любые советы по его улучшению в целом или, в частности, отсутствие поддержки последовательных точек dotdot будут приветствоваться.

В настоящее время это работает с моими ограниченными примерами, но я думаю, что это можно улучшить. Он не может обрабатывать непоследовательные каталоги «..», и я, вероятно, делаю много расточительных (и подверженных ошибкам) ​​вещей, которые мне, вероятно, не нужно делать, потому что я немного взломан.

Я нашел множество примеров преобразования других типов относительных путей с использованием других языков, но ни одна из них, похоже, не соответствовала моей ситуации.

Это мой пример пути, которые мне нужно преобразовать, от:

//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 не появился на первой странице одного из многих вариантов поисковых запросов Google, которые я сделал для «ruby convert по отношению к абсолютному пути». Благодаря! – wonderfulthunk

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