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
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.
En fait, il y a une fonction qui retourne exactement ce que vous voulez
print(os.path.basename(your_path))
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
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
En python 3
>>> from pathlib import Path
>>> Path("/tmp/d/a.dat").name
'a.dat'
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.
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.
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']
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))
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 .
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])
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
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.
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.
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.