web-dev-qa-db-fra.com

Extraire le nom du fichier du chemin, peu importe le format os/chemin

Quelle bibliothèque Python puis-je utiliser pour extraire les noms de fichiers des chemins, peu importe le système d'exploitation ou le format de chemin

Par exemple, j'aimerais que tous ces chemins me renvoient c:

a/b/c/
a/b/c
\a\b\c
\a\b\c\
a\b\c
a/b/../../a/b/c/
a/b/../../a/b/c
515
Jerome

Utiliser os.path.split ou os.path.basename, comme le suggèrent d'autres personnes, ne fonctionnera pas dans tous les cas: si vous exécutez le script sous Linux et tentez de traiter un chemin classique, de style Windows, il échouera.

Les chemins Windows peuvent utiliser une barre oblique inverse ou une barre oblique comme séparateur de chemin. Par conséquent, le module ntpath (équivalent à os.path sous Windows) fonctionnera pour tous.(1) chemins sur toutes les plateformes.

import ntpath
ntpath.basename("a/b/c")

Bien sûr, si le fichier se termine par une barre oblique, le nom de base sera vide, alors créez votre propre fonction pour la gérer:

def path_leaf(path):
    head, tail = ntpath.split(path)
    return tail or ntpath.basename(head)

Vérification:

>>> paths = ['a/b/c/', 'a/b/c', '\\a\\b\\c', '\\a\\b\\c\\', 'a\\b\\c', 
...     'a/b/../../a/b/c/', 'a/b/../../a/b/c']
>>> [path_leaf(path) for path in paths]
['c', 'c', 'c', 'c', 'c', 'c', 'c']


(1) Un inconvénient: les noms de fichiers Linux peuvent contenir des barres obliques inverses . Donc, sur linux, r'a/b\c' fait toujours référence au fichier b\c dans le dossier a, tandis que sous Windows, il fait toujours référence au fichier c dans le sous-dossier b du dossier a. Ainsi, lorsque des barres obliques inverses et ascendantes sont utilisées dans un chemin, vous avez besoin de connaître la plate-forme associée pour pouvoir l’interpréter correctement. En pratique, il est généralement prudent de supposer que c'est un chemin Windows car les barres obliques inverses sont rarement utilisées dans les noms de fichiers Linux, mais gardez cela à l'esprit lorsque vous codez pour ne pas créer de failles de sécurité accidentelles.

561
Lauritz V. Thaulow

En fait, il y a une fonction qui retourne exactement ce que vous voulez

print(os.path.basename(your_path))
864
stranac

os.path.split est la fonction que vous recherchez

head, tail = os.path.split("/tmp/d/a.dat")

>>> print(tail)
a.dat
>>> print(head)
/tmp/d
166
Jakob Bowyer
import os
head, tail = os.path.split(p)
print tail

Supposons que p est la chaîne d'entrée, la queue est ce que vous voulez.

Voir la documentation du module python os pour plus de détails

32
number5

En python 3

>>> from pathlib import Path    
>>> Path("/tmp/d/a.dat").name
'a.dat'
27
Kishan B

Dans votre exemple, vous devrez également supprimer la barre oblique de droite à droite pour renvoyer c:

>>> import os
>>> path = 'a/b/c/'
>>> path = path.rstrip(os.sep) # strip the slash from the right side
>>> os.path.basename(path)
'c'

Deuxième niveau:

>>> os.path.filename(os.path.dirname(path))
'b'

mise à jour: Je pense que lazyr a fourni la bonne réponse. Mon code ne fonctionnera pas avec les chemins de type Windows sur les systèmes Unix et vice-versa avec les chemins de type Unix sur le système Windows.

10
Ski
fname = str("C:\Windows\Paint.exe").split('\\')[-1:][0]

cela retournera: Paint.exe

changez la valeur sep de la fonction split en fonction de votre chemin ou de votre système d'exploitation.

7
Eslam Hamouda

Cela fonctionne pour Linux et Windows aussi bien avec la bibliothèque standard

paths = ['a/b/c/', 'a/b/c', '\\a\\b\\c', '\\a\\b\\c\\', 'a\\b\\c',
         'a/b/../../a/b/c/', 'a/b/../../a/b/c']

def path_leaf(path):
    return path.strip('/').strip('\\').split('/')[-1].split('\\')[-1]

[path_leaf(path) for path in paths]

Résultats:

['c', 'c', 'c', 'c', 'c', 'c', 'c']
7
Csabka

Je n'ai jamais vu de double-backslashed path, existe-t-il? La fonctionnalité intégrée du module python os échoue pour ceux-ci. Tous les autres fonctionnent, ainsi que la mise en garde donnée par vous avec os.path.normpath():

paths = ['a/b/c/', 'a/b/c', '\\a\\b\\c', '\\a\\b\\c\\', 'a\\b\\c', 
...     'a/b/../../a/b/c/', 'a/b/../../a/b/c', 'a/./b/c', 'a\b/c']
for path in paths:
    os.path.basename(os.path.normpath(path))
5
PythoNic

Voici une solution uniquement pour les expressions rationnelles, qui semble fonctionner avec n'importe quel chemin d'accès au système d'exploitation.

Aucun autre module n'est nécessaire, et aucun prétraitement n'est nécessaire non plus:

import re

def extract_basename(path):
  """Extracts basename of a given path. Should Work with any OS Path on any OS"""
  basename = re.search(r'[^\\/]+(?=[\\/]?$)', path)
  if basename:
    return basename.group(0)


paths = ['a/b/c/', 'a/b/c', '\\a\\b\\c', '\\a\\b\\c\\', 'a\\b\\c',
         'a/b/../../a/b/c/', 'a/b/../../a/b/c']

print([extract_basename(path) for path in paths])
# ['c', 'c', 'c', 'c', 'c', 'c', 'c']


extra_paths = ['C:\\', 'alone', '/a/space in filename', 'C:\\multi\nline']

print([extract_basename(path) for path in extra_paths])
# ['C:', 'alone', 'space in filename', 'multi\nline']

La regex peut être testée ici .

3
Eric Duminil

Le séparateur Windows peut être dans un nom de fichier Unix ou un chemin Windows. Le séparateur Unix ne peut exister que dans le chemin Unix. La présence d'un séparateur Unix indique un chemin non-Windows.

Le suivant séparera (séparateur de fin) par le séparateur spécifique au SE, puis se séparera et retournera la valeur la plus à droite. C'est moche, mais simple, basé sur l'hypothèse ci-dessus. Si l'hypothèse est incorrecte, veuillez mettre à jour et je mettrai à jour cette réponse pour qu'elle corresponde aux conditions plus précises.

a.rstrip("\\\\" if a.count("/") == 0 else '/').split("\\\\" if a.count("/") == 0 else '/')[-1]

exemple de code:

b = ['a/b/c/','a/b/c','\\a\\b\\c','\\a\\b\\c\\','a\\b\\c','a/b/../../a/b/c/','a/b/../../a/b/c']

for a in b:

    print (a, a.rstrip("\\" if a.count("/") == 0 else '/').split("\\" if a.count("/") == 0 else '/')[-1])
3
dusc2don

Peut-être juste ma solution tout-en-un sans important quelque chose de nouveau (tenez compte du fichier temporaire pour la création de fichiers temporaires: D)

import tempfile
abc = tempfile.NamedTemporaryFile(dir='/tmp/')
abc.name
abc.name.replace("/", " ").split()[-1] 

Obtenir les valeurs de abc.name sera une chaîne comme ceci: '/tmp/tmpks5oksk7'Alors, je peux remplacer le / par un espace .replace("/", " "), puis appeler split(). Cela va retourner une liste et je reçois le dernier élément de la liste avec [-1]

Pas besoin d'importer un module. 

meilleures salutations

4k3nd0

2
Akendo

Par souci d'exhaustivité, voici la solution pathlib pour Python 3.2+:

>>> from pathlib import PureWindowsPath

>>> paths = ['a/b/c/', 'a/b/c', '\\a\\b\\c', '\\a\\b\\c\\', 'a\\b\\c', 
...          'a/b/../../a/b/c/', 'a/b/../../a/b/c']

>>> [PureWindowsPath(path).name for path in paths]
['c', 'c', 'c', 'c', 'c', 'c', 'c']

Cela fonctionne sous Windows et Linux.

1
Morgoth

Si votre chemin de fichier ne se termine pas par "/" et que les répertoires sont séparés par "/", utilisez le code suivant. Comme nous le savons généralement, le chemin ne se termine pas par "/".

import os
path_str = "/var/www/index.html"
print(os.path.basename(path_str))

Mais dans certains cas, comme les URL se terminent par "/", utilisez le code suivant

import os
path_str = "/home/some_str/last_str/"
split_path = path_str.rsplit("/",1)
print(os.path.basename(split_path[0]))

mais quand votre chemin est indiqué par "\" que vous trouvez généralement dans les chemins Windows, vous pouvez utiliser les codes suivants

import os
path_str = "c:\\var\www\index.html"
print(os.path.basename(path_str))

import os
path_str = "c:\\home\some_str\last_str\\"
split_path = path_str.rsplit("\\",1)
print(os.path.basename(split_path[0]))

Vous pouvez combiner les deux en une seule fonction en vérifiant le type de système d'exploitation et en renvoyant le résultat.

1
Santosh kumar Manda

En Python 2 et 3, utilisez le module pathlib2 :

import posixpath  # to generate unix paths
from pathlib2 import PurePath, PureWindowsPath, PurePosixPath

def path2unix(path, nojoin=True, fromwinpath=False):
    """From a path given in any format, converts to posix path format
    fromwinpath=True forces the input path to be recognized as a Windows path (useful on Unix machines to unit test Windows paths)"""
    if not path:
        return path
    if fromwinpath:
        pathparts = list(PureWindowsPath(path).parts)
    else:
        pathparts = list(PurePath(path).parts)
    if nojoin:
        return pathparts
    else:
        return posixpath.join(*pathparts)

Usage:

In [9]: path2unix('lala/lolo/haha.dat')
Out[9]: ['lala', 'lolo', 'haha.dat']

In [10]: path2unix(r'C:\lala/lolo/haha.dat')
Out[10]: ['C:\\', 'lala', 'lolo', 'haha.dat']

In [11]: path2unix(r'C:\lala/lolo/haha.dat') # works even with malformatted cases mixing both Windows and Linux path separators
Out[11]: ['C:\\', 'lala', 'lolo', 'haha.dat']

Avec votre test:

In [12]: testcase = paths = ['a/b/c/', 'a/b/c', '\\a\\b\\c', '\\a\\b\\c\\', 'a\\b\\c',
    ...: ...     'a/b/../../a/b/c/', 'a/b/../../a/b/c']

In [14]: for t in testcase:
    ...:     print(path2unix(t)[-1])
    ...:
    ...:
c
c
c
c
c
c
c

L'idée ici est de convertir tous les chemins en la représentation interne unifiée de pathlib2, avec différents décodeurs selon la plate-forme. Heureusement, pathlib2 inclut un décodeur générique appelé PurePath qui devrait fonctionner sur n'importe quel chemin. Si cela ne fonctionne pas, vous pouvez forcer la reconnaissance du chemin Windows à l'aide de fromwinpath=True. Cela divisera la chaîne d'entrée en parties, la dernière étant la feuille que vous recherchez, d'où la path2unix(t)[-1].

Si l'argument nojoin=False est créé, le chemin sera joint, de sorte que la sortie est simplement la chaîne d'entrée convertie au format Unix, ce qui peut être utile pour comparer les sous-chemins entre plates-formes.

0
gaborous