os.path.commonprefix () und os.path.relpath () sind deine Freunde:
>>> print os.path.commonprefix(['/usr/var/log', '/usr/var/security'])
'/usr/var'
>>> print os.path.commonprefix(['/tmp', '/usr/var']) # No common prefix: the root is the common prefix
'/'
Sie können also testen, ob das gemeinsame Präfix einer der Pfade ist, dh ob einer der Pfade ein gemeinsamer Vorfahr ist:
paths = […, …, …]
common_prefix = os.path.commonprefix(list_of_paths)
if common_prefix in paths:
…
Sie können dann die relativen Pfade finden:
relative_paths = [os.path.relpath(path, common_prefix) for path in paths]
Mit dieser Methode können Sie sogar mehr als zwei Pfade verarbeiten und testen, ob alle Pfade unter einem von ihnen liegen.
PS : Je nachdem, wie Ihre Pfade aussehen, möchten Sie möglicherweise zuerst eine Normalisierung durchführen (dies ist in Situationen nützlich, in denen nicht bekannt ist, ob sie immer mit '/' enden oder nicht oder ob einige der Pfade relativ sind). Relevante Funktionen sind os.path.abspath () und os.path.normpath () .
PPS : Wie Peter Briggs in den Kommentaren erwähnt hat, kann der oben beschriebene einfache Ansatz fehlschlagen:
>>> os.path.commonprefix(['/usr/var', '/usr/var2/log'])
'/usr/var'
obwohl /usr/var
ist kein allgemeines Präfix der Pfade. Das Erzwingen, dass alle Pfade vor dem Aufruf mit '/' enden, commonprefix()
löst dieses (spezifische) Problem.
PPPS : Wie in bluenote10 erwähnt, löst das Hinzufügen eines Schrägstrichs das allgemeine Problem nicht. Hier ist seine Folgefrage: Wie kann man den Irrtum von Pythons os.path.commonprefix umgehen?
PPPPS : Ab Python 3.4 haben wir pathlib , ein Modul, das eine sanere Pfadmanipulationsumgebung bietet. Ich vermute, dass das gemeinsame Präfix eines Satzes von Pfaden erhalten werden kann, indem alle Präfixe jedes Pfades (mit PurePath.parents()
) abgerufen , der Schnittpunkt aller dieser übergeordneten Sätze genommen und das längste gemeinsame Präfix ausgewählt werden.
PPPPPS : Python 3.5 hat eine geeignete Lösung für diese Frage eingeführt : os.path.commonpath()
, die einen gültigen Pfad zurückgibt.
commonprefix
, wie z. B. dem allgemeinen Präfix für/usr/var/log
und/usr/var2/log
wird zurückgegeben als/usr/var
- was wahrscheinlich nicht das ist, was Sie erwarten würden. (Es ist auch möglich, Pfade zurückzugeben, die keine gültigen Verzeichnisse sind.)['/usr/var1/log/', '/usr/var2/log/']
?os.path.relpath
::Wenn also der relative Pfad mit beginnt
'..'
, bedeutet dies, dass der zweite Pfad nicht vom ersten Pfad abstammt.In Python3 können Sie Folgendes verwenden
PurePath.relative_to
:quelle
os.pardir
ist robuster als das Überprüfen auf..
(vereinbart, es gibt jedoch nicht viele andere Konventionen).os.relpath
es mächtiger, da es funktioniert..
undPurePath.relative_to()
nicht? Vermisse ich etwasEine andere Option ist
quelle
os.pardir
vor den beiden möglichen resultierenden relativen Pfaden vorhanden ist).Eine Zusammenfassung von Jmes Vorschlag mit pathlib in Python 3.
quelle
dir1.relative_to(dir2)
gibt PosixPath ( ‚‘) , wenn sie gleich sind. Wenn Sieif dir2 in dir1.parents
dann verwenden, wird der Identitätsfall ausgeschlossen. Wenn jemand Pfade vergleicht und ausführen möchte,relative_to()
wenn er pfadkompatibel ist, istif dir2 in (dir1 / 'x').parents
oder möglicherweise eine bessere Lösungif dir2 in dir1.parents or dir2 == dir1
. Dann werden alle Fälle von Pfadkompatibilität abgedeckt.Pure Python2 ohne dep:
quelle
cwd
undpath
sind das gleiche. es sollte zuerst prüfen, ob diese beiden gleich sind und entweder""
oder"."
Bearbeiten: Siehe jmes Antwort für den besten Weg mit Python3.
Mit pathlib haben Sie folgende Lösung:
Angenommen, wir möchten überprüfen, ob
son
es sich um einen Nachkommen von handeltparent
, und beide sindPath
Objekte. Wir können eine Liste der Teile im Pfad mit erhaltenlist(parent.parts)
. Dann überprüfen wir einfach, ob der Anfang des Sohnes der Liste der Segmente des Elternteils entspricht.Wenn Sie den verbleibenden Teil erhalten möchten, können Sie dies einfach tun
Es ist eine Zeichenfolge, aber Sie können sie natürlich als Konstruktor eines anderen Path-Objekts verwenden.
quelle
parent in son.parents
und wenn ja , den Rest mitson.relative_to(parent)
.