Могу ли я сделать этот слепой относительно преобразования абсолютного пути (для путей выполнения депо) лучше? - PullRequest
4 голосов
/ 14 мая 2010

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

Я прошел ряд (возможно, глупых) итераций, пытаясь заставить его работать - в основном несколько вариантов итераций по массиву папок и попытки удаления 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

Ответы [ 3 ]

22 голосов
/ 14 мая 2010

Давайте не будем изобретать велосипед ... 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"]
2 голосов
/ 14 мая 2010

Почему бы просто не использовать 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('/')
1 голос
/ 14 мая 2010

Код 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.

...