2010-05-14 9 views
3

Je dois "aveuglément" (c'est-à-dire sans accès au système de fichiers, dans ce cas le serveur de contrôle de source) convertir certains chemins relatifs en chemins absolus. Je joue donc avec les dotdots et les indices. Pour ceux qui sont curieux, j'ai un fichier journal produit par l'outil de quelqu'un d'autre qui sort parfois des chemins relatifs, et pour des raisons de performance je ne veux pas accéder au serveur de contrôle source où les chemins sont localisés pour vérifier s'ils sont valides facilement les convertir en leurs équivalents de chemin absolu. J'ai traversé un certain nombre d'itérations (probablement idiotes) en essayant de le faire fonctionner - principalement quelques variations d'itération sur le tableau de dossiers et en essayant delete_at (index) et delete_at (index-1) mais mon index a continué à incrémenter pendant que je supprimais des éléments du tableau sous moi-même, ce qui ne fonctionnait pas pour les cas avec plusieurs dotdots. Tous les conseils sur l'amélioration en général ou spécifiquement le manque de soutien dotdot non-consécutif seraient les bienvenus.Est-ce que je pourrais faire ce blind par rapport à la conversion de chemin absolu (pour les chemins de dépôt perforce) mieux?

Actuellement, cela fonctionne 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 je fais probablement beaucoup de choses inutiles (et sujettes aux erreurs) que je n'ai probablement pas besoin de faire parce que je suis un peu un hack.

J'ai trouvé beaucoup d'exemples de conversion d'autres types de chemins relatifs en utilisant d'autres langages, mais aucun d'entre eux ne semblait correspondre à ma situation.

Ce sont mes exemples 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 

Répondre

19

Let réinventons pas la roue .. File.expand_path fait cela 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"] 
+0

Wow, je suis étonné ce fichier.expand_path n'est pas apparu sur la première page de l'une des nombreuses variantes de recherches google que j'ai faites pour "ruby convert relatif au chemin absolu". Merci! – wonderfulthunk

1

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 dans Ruby.

2

Pourquoi ne pas simplement 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('/')