Pourrais-je faire aveugle par rapport à la conversion de chemin absolu (pour les chemins de dépôt Perforce) mieux?
-
26-09-2019 - |
Question
Je dois « aveuglément » (à savoir sans accès au système de fichiers, dans ce cas, le serveur de contrôle de code source) convertir des chemins relatifs à des chemins absolus. Donc, je joue avec dotdots et indices. Pour ceux qui sont curieux, j'ai un fichier journal produit par quelqu'un d'outil d'autre que de parfois des chemins relatifs, et pour des raisons de performance, je ne veux pas accéder au serveur de contrôle de code source où les chemins sont situés pour vérifier si elles sont valides et plus facilement les convertir à leurs équivalents de chemin absolu.
Je suis passé par plusieurs (probablement folles) itérations essayant de le faire au travail - la plupart du temps quelques variations de itérer sur le tableau de dossiers et d'essayer delete_at (index) et delete_at (index 1), mais mon index gardé incrémenter alors que je supprimait les éléments du tableau de sous moi-même, ce qui n'a pas fonctionné pour les cas avec plusieurs dotdots. Tous les conseils sur l'amélioration en général ou en particulier le manque de soutien de pointpoint non consécutifs serait la bienvenue.
Actuellement, ce travaille avec mes exemples limités, mais je pense qu'il pourrait être amélioré. Il ne peut pas gérer les répertoires non consécutifs « .. », et que je fais sans doute beaucoup de choses inutiles (et sujettes à l'erreur) que je ne doute pas besoin de faire parce que je suis un peu un hack.
Je l'ai trouvé beaucoup d'exemples de conversion d'autres types de chemins relatifs à l'aide d'autres langues, mais aucun d'entre eux semblait ma situation.
Ce sont mes exemple des chemins que je dois convertir, de:
//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
Et mon script:
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
La solution
Il ne faut pas réinventer la roue ... File.expand_path
fait pour vous:
[
'//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"]
Autres conseils
Pourquoi ne pas utiliser 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"
Pour une solution DIY en utilisant des tableaux, cela vient à l'esprit (fonctionne aussi pour vos exemples):
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('/')
code 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)
impressions:
//depot/bar/single.c
//depot/other/double.c
//depot/else/more/triple.c
Vous pouvez utiliser le même algorithme Ruby.