251 votes

Comment diviser un chemin d'accès en ses composants en Python ?

J'ai une variable de type chaîne qui représente un chemin d'accès, par exemple :

var = "d:\stuff\morestuff\furtherdown\THEFILE.txt"

Je veux diviser cette chaîne en :

[ "d", "stuff", "morestuff", "furtherdown", "THEFILE.txt" ]

J'ai essayé d'utiliser split() et replace() mais soit ils ne traitent que la première barre oblique inverse, soit ils insèrent des chiffres hexadécimaux dans la chaîne.

J'ai besoin de convertir cette variable chaîne en une chaîne brute afin de pouvoir l'analyser.

Quelle est la meilleure façon de procéder ?

Je dois également ajouter que le contenu de var c'est-à-dire le chemin que j'essaie d'analyser, est en fait la valeur de retour d'une requête en ligne de commande. Ce ne sont pas des données de chemin que je génère moi-même. Elles sont stockées dans un fichier, et l'outil de ligne de commande ne va pas échapper aux antislashes.

8 votes

En examinant ces réponses, rappelez-vous que os.path.split ne fonctionne pas pour vous parce que vous n'échappez pas cette chaîne correctement.

0 votes

Vous devez échapper la chaîne ou utiliser rawstring : r"d:\stuff\morestuff\furtherdown\THEFILE.txt" pour éviter des choses comme \s être mal interprétées.

457voto

Tompa Points 123

Merci

Je ferais

import os
path = os.path.normpath(path)
path.split(os.sep)

Tout d'abord, normalisez la chaîne de chemin d'accès en une chaîne appropriée pour le système d'exploitation. Ensuite, os.sep doit être sûr pour être utilisé comme délimiteur dans la fonction split de la chaîne.

35 votes

La seule vraie réponse : il est apparu . La solution canonique est la plus simple, bien sûr. Regardez ! Car elle est élégante et contumace et ne présente pas de cas limites insupportables.

46 votes

En une phrase, os.path.normpath(a_path).split(os.path.sep)

3 votes

Cela ne semble pas fonctionner pour path = Root. Dans ce cas, le résultat de path.split est ['','']. En fait, en général, cette solution split() donne un répertoire le plus à gauche avec un nom de chaîne vide (qui pourrait être remplacé par le slash approprié). Le problème principal est qu'une simple barre oblique (vers l'avant ou vers l'arrière, selon le système d'exploitation) est l'équivalent d'un nom de répertoire. nom du répertoire Root, alors qu'ailleurs dans le chemin, il s'agit d'un fichier séparateur .

225voto

J'ai été piqué de nombreuses fois par des personnes qui écrivaient leurs propres fonctions de manipulation de chemins et se trompaient. Espaces, barres obliques, barres obliques inversées, deux-points -- les possibilités de confusion ne sont pas infinies, mais les erreurs sont facilement commises de toute façon. C'est pourquoi je suis très attaché à l'utilisation des caractères suivants os.path et le recommander sur cette base.

(Cependant, le chemin de la vertu n'est pas le plus facile à emprunter, et beaucoup de gens, lorsqu'ils le découvrent, sont tentés de prendre un chemin glissant qui mène directement à la damnation. Elles ne s'en rendront compte que lorsqu'un jour tout s'écroulera, et qu'elles -- ou, plus probablement, quelqu'un d'autre -- devront comprendre pourquoi tout est allé de travers, et qu'il s'avérera que quelqu'un a créé un nom de fichier qui mélange des slashs et des backslashes -- et qu'une personne suggérera que la réponse est "ne pas faire ça". Ne soyez pas l'une de ces personnes. Sauf pour celui qui a mélangé les slashs et les backslashes -- vous pouvez être eux si vous voulez).

Vous pouvez obtenir le lecteur et le chemin+fichier comme ceci :

drive,path_and_file=os.path.splitdrive(path)

Obtenez le chemin et le fichier :

path,file=os.path.split(path_and_file)

Obtenir les noms des dossiers individuels n'est pas particulièrement pratique, mais c'est le genre d'inconfort moyennement honnête qui augmente le plaisir de trouver plus tard quelque chose qui fonctionne vraiment bien :

folders=[]
while 1:
    path,folder=os.path.split(path)

    if folder!="":
        folders.append(folder)
    else:
        if path!="":
            folders.append(path)

        break

folders.reverse()

(Cela fait apparaître un "\" au début de folders si le chemin était initialement absolu. Vous pourriez perdre un peu de code si vous ne vouliez pas cela).

0 votes

@brone - Je préfère utiliser cette solution, plutôt que d'avoir à se soucier de l'échappement de la barre oblique inverse. merci !

0 votes

Je me fais l'écho de votre sentiment - os.path devrait être utilisé à chaque fois que vous n'écrivez pas seulement un cas unique.

0 votes

@brone - Je pensais que si je sélectionnais votre réponse, vous obtiendriez la prime ? ?? Désolé, il semble que SO ait sélectionné automatiquement la réponse pour la prime - les points devaient vous être attribués.

92voto

Maciek D. Points 631

Vous pouvez simplement utiliser l'approche la plus pythique (IMHO) :

import os

your_path = r"d:\stuff\morestuff\furtherdown\THEFILE.txt"
path_list = your_path.split(os.sep)
print path_list

Ce qui vous donnera :

['d:', 'stuff', 'morestuff', 'furtherdown', 'THEFILE.txt']

L'indice ici est d'utiliser os.sep au lieu de '\\' ou '/' car cela le rend indépendant du système.

Pour supprimer les deux points de la lettre du lecteur (bien que je ne voie pas pourquoi vous voudriez le faire), vous pouvez écrire :

path_list[0] = path_list[0][0]

27 votes

Cela fonctionne some times . D'autres fois (du moins sous Windows), vous trouverez des chemins qui ressemblent à ceci folder\folder2\folder3/file.txt . Il vaut mieux d'abord normaliser (os.path.normpath) le chemin et ensuite le diviser.

8 votes

Cette réponse était presque là. Comme vikki suggère que le fait de ne pas normaliser les noms de chemin avant de séparer les chaînes de caractères est fatal pour les cas limites courants (par ex, /foo//bar ). Voir Tompa 's réponse pour une solution plus robuste.

12voto

user1556435 Points 148

Pour une solution un peu plus concise, considérez ce qui suit :

def split_path(p):
    a,b = os.path.split(p)
    return (split_path(a) if len(a) and len(b) else []) + [b]

0 votes

Voici ma solution préférée à ce problème. Très bien.

2 votes

Cela ne fonctionne pas si le chemin se termine par / . En outre, il vous donne une chaîne vide au début de la liste si votre chemin commence par /

11voto

Craig Trader Points 8924

Le problème ici commence avec la façon dont vous créez la chaîne en premier lieu.

a = "d:\stuff\morestuff\furtherdown\THEFILE.txt"

De cette façon, Python essaie de les mettre dans un cas particulier : \s , \m , \f et \T . Dans votre cas, \f est traité comme un saut de page (0x0C) alors que les autres antislashs sont traités correctement. Ce que vous devez faire est l'un des suivants :

b = "d:\\stuff\\morestuff\\furtherdown\\THEFILE.txt"      # doubled backslashes
c = r"d:\stuff\morestuff\furtherdown\THEFILE.txt"         # raw string, no doubling necessary

Une fois que vous aurez divisé l'un ou l'autre, vous obtiendrez le résultat souhaité.

0 votes

@W. Craig Trader - merci, mais ce chemin n'est pas un chemin que je génère moi-même - il me revient d'un autre programme et je dois stocker ces données dans une variable. Je ne sais pas comment convertir les données stockées dans une variable en "texte brut".

0 votes

Le "texte brut" n'existe pas... c'est juste la façon dont on le représente dans la source. Soit vous ajoutez r"" à la chaîne de caractères, soit vous la passez dans .replace('). \\ ', '/')

0 votes

@BeeBand, comment récupérez-vous les données de l'autre programme ? Les lisez-vous depuis un fichier, un tube, un socket ? Si c'est le cas, vous n'avez pas besoin de faire quoi que ce soit de compliqué ; la seule raison de doubler les antislashes ou d'utiliser des chaînes brutes est de placer des constantes de chaîne dans le code Python. D'un autre côté, si l'autre programme génère des doubles barres obliques inverses, vous voudrez les nettoyer avant de diviser votre chemin.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X