Могу ли я сделать этот слепой относительно абсолютной преобразования пути (для Perforce Paths Paths) лучше?
-
26-09-2019 - |
Вопрос
Мне нужно «слепо» (то есть без доступа к файловой системе, в этом случае сервер управления источником) преобразуют некоторые относительные пути к абсолютному пути. Так что я играю с дотдотами и индексами. Для тех, кто любопытно, у меня есть файл журнала, созданный чужом инструментом, который иногда выводит относительные пути, и по причинам производительности я не хочу получить доступ к серверу исходника, где пути расположены, чтобы проверить, они действительны и другие легко преобразовать их в свои эквиваленты абсолютного пути.
Я прошел через ряд (вероятно, глупых) итераций, пытающихся заставить его работать - в основном несколько вариаций итерации по массиву папок и попытки delete_at (индекс) и 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
Решение
Давайте не переимененным колесом ... 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
:
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('/')
Код 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.