webentwicklung-frage-antwort-db.com.de

Extrahieren Sie den Dateinamen aus dem Pfad, unabhängig vom OS-/Pfadformat

Welche Python-Bibliothek kann ich verwenden, um Dateinamen aus Pfaden zu extrahieren, unabhängig vom Betriebssystem oder Pfadformat?

Zum Beispiel möchte ich, dass all diese Pfade mich c zurückgeben:

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

Die Verwendung von os.path.split oder os.path.basename funktioniert nicht in allen Fällen: Wenn Sie das Skript unter Linux ausführen und versuchen, einen klassischen Windows-Pfad zu verarbeiten, schlägt dies fehl.

Windows-Pfade können entweder Backslash oder Forward Slash als Pfadtrennzeichen verwenden. Daher funktioniert das ntpath -Modul (das unter Windows os.path entspricht) für alle(1) Pfade auf allen Plattformen.

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

Wenn die Datei mit einem Schrägstrich endet, ist der Basisname natürlich leer. Erstellen Sie daher Ihre eigene Funktion, um damit umzugehen:

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

Nachprüfung:

>>> 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) Es gibt eine Einschränkung: Linux-Dateinamen können Backslashes enthalten. Unter Linux bezieht sich r'a/b\c' immer auf die Datei b\c im Ordner a, während sich unter Windows immer auf die Datei c im Ordner b bezieht. Unterordner des Ordners a. Wenn in einem Pfad sowohl Schrägstriche als auch umgekehrte Schrägstriche verwendet werden, müssen Sie die zugehörige Plattform kennen , um sie korrekt interpretieren zu können. In der Praxis kann davon ausgegangen werden, dass es sich um einen Windows-Pfad handelt, da Backslashes in Linux-Dateinamen selten verwendet werden. Beachten Sie dies jedoch, wenn Sie Code verwenden, um keine versehentlichen Sicherheitslücken zu schaffen.

646

Eigentlich gibt es eine Funktion , die genau das zurückgibt, was Sie wollen

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

os.path.split ist die Funktion, nach der Sie suchen

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

Angenommen, p ist die Eingabezeichenfolge, Schwanz ist, was Sie wollen.

Weitere Informationen finden Sie unter python os-Moduldokumente

32
number5

In Python 3

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

In Ihrem Beispiel müssen Sie auch den Schrägstrich rechts von der rechten Seite entfernen, um c zurückzugeben:

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

Zweites Level:

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

update: Ich denke, lazyr hat die richtige Antwort gegeben. Mein Code funktioniert nicht mit Windows-ähnlichen Pfaden auf Unix-Systemen und umgekehrt mit Unix-ähnlichen Pfaden auf Windows-Systemen.

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

dies wird zurückgeben: Paint.exe

Ändern Sie den sep-Wert der Split-Funktion in Bezug auf Ihren Pfad oder Ihr Betriebssystem.

7
Eslam Hamouda

Dies funktioniert für Linux und Windows sowie für die Standardbibliothek

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]

Ergebnisse:

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

Ich habe noch nie doppelte Backslash-Pfade gesehen. Gibt es sie? Die eingebaute Funktion des Python-Moduls os schlägt für diese fehl. Alle anderen arbeiten, auch der von Ihnen mit os.path.normpath() gegebene Vorbehalt:

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

Hier ist eine regex-only-Lösung, die mit jedem Betriebssystempfad unter jedem Betriebssystem zu funktionieren scheint.

Es wird kein anderes Modul benötigt und es ist auch keine Vorverarbeitung erforderlich:

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']

Der Regex kann hier getestet werden.

3
Eric Duminil

Das Windows-Trennzeichen kann sich in einem Unix-Dateinamen oder Windows-Pfad befinden. Das Unix-Trennzeichen kann nur im Unix-Pfad vorhanden sein. Das Vorhandensein eines Unix-Separators zeigt einen Nicht-Windows-Pfad an.

Im Folgenden wird das nachlaufspezifische Trennzeichen entfernt (nachgestelltes Trennzeichen), anschließend wird der Wert ganz rechts ausgegeben. Es ist hässlich, aber basierend auf der obigen Annahme einfach. Wenn die Annahme falsch ist, aktualisieren Sie sich bitte, und ich werde diese Antwort aktualisieren, um den genaueren Bedingungen zu entsprechen.

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

beispielcode:

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

Vielleicht nur meine All-in-One-Lösung ohne wichtige Neuerungen (siehe temporäre Dateien zum Erstellen temporärer Dateien: D)

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

Die Werte von abc.name erhalten, ist eine Zeichenfolge wie folgt: '/tmp/tmpks5oksk7'So Ich kann den / durch ein Leerzeichen .replace("/", " ") ersetzen und dann split() aufrufen. Das gibt eine Liste zurück und ich bekomme das Letzte Element der Liste mit [-1]

Es muss kein Modul importiert werden. 

freundliche Grüße

4k3nd0

2
Akendo

Der Vollständigkeit halber ist hier die pathlib-Lösung für 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']

Dies funktioniert sowohl unter Windows als auch unter Linux.

1
Morgoth

Wenn Ihr Dateipfad nicht mit "/" und durch "/" getrennten Verzeichnissen endet, verwenden Sie den folgenden Code. Wie wir wissen, endet der Pfad normalerweise nicht mit "/".

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

In einigen Fällen enden jedoch URLs mit "/" und verwenden Sie dann den folgenden Code

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

wenn Ihr Pfad jedoch durch "\" abgespeichert wird, den Sie normalerweise in Windows-Pfaden finden, können Sie die folgenden Codes verwenden

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]))

Sie können beide Funktionen in einer Funktion kombinieren, indem Sie den Betriebssystemtyp überprüfen und das Ergebnis zurückgeben.

1

Verwenden Sie in Python 2 und 3 das Modul 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)

Verwendungszweck:

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']

Mit deinem Testfall:

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

Die Idee ist hier, alle Pfade in die einheitliche interne Darstellung von pathlib2 umzuwandeln, wobei je nach Plattform unterschiedliche Decoder erforderlich sind. Zum Glück enthält pathlib2 einen generischen Decoder mit dem Namen PurePath, der auf jedem Pfad funktionieren sollte. Falls dies nicht funktioniert, können Sie die Erkennung des Windows-Pfads mit fromwinpath=True erzwingen. Dadurch wird die Eingabezeichenfolge in Teile aufgeteilt. Der letzte ist das Blatt, nach dem Sie suchen, daher die path2unix(t)[-1].

Wenn das Argument nojoin=False verwendet wird, wird der Pfad zurückverknüpft, sodass die Ausgabe einfach die in ein Unix-Format konvertierte Eingabezeichenfolge ist. Dies kann nützlich sein, um Unterpfade plattformübergreifend zu vergleichen.

0
gaborous