os.path.commonprefix () i os.path.relpath () to Twoi przyjaciele:
>>> 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
'/'
Możesz więc sprawdzić, czy wspólny prefiks jest jedną ze ścieżek, tj. Czy jedna ze ścieżek jest wspólnym przodkiem:
paths = […, …, …]
common_prefix = os.path.commonprefix(list_of_paths)
if common_prefix in paths:
…
Następnie możesz znaleźć ścieżki względne:
relative_paths = [os.path.relpath(path, common_prefix) for path in paths]
Za pomocą tej metody można nawet obsłużyć więcej niż dwie ścieżki i sprawdzić, czy wszystkie ścieżki znajdują się poniżej jednej z nich.
PS : w zależności od tego, jak wyglądają Twoje ścieżki, możesz najpierw zechcieć przeprowadzić pewną normalizację (jest to przydatne w sytuacjach, gdy nie wiadomo, czy zawsze kończą się znakiem „/”, czy też nie, lub jeśli niektóre ścieżki są względne). Odpowiednie funkcje obejmują os.path.abspath () i os.path.normpath () .
PPS : jak wspomniał w komentarzach Peter Briggs, proste podejście opisane powyżej może się nie powieść:
>>> os.path.commonprefix(['/usr/var', '/usr/var2/log'])
'/usr/var'
mimo że nie/usr/var
jest to wspólny prefiks ścieżek. Wymuszenie przed wywołaniem wszystkich ścieżek kończących się znakiem „/” rozwiązuje ten (konkretny) problem.commonprefix()
PPPS : jak wspomniano w bluenote10, dodanie ukośnika nie rozwiązuje ogólnego problemu. Oto jego kolejne pytanie: Jak obejść błąd związany z os.path.commonprefix w języku Python?
PPPPS : począwszy od Pythona 3.4, mamy pathlib , moduł zapewniający bardziej rozsądne środowisko do manipulacji ścieżkami. Myślę, że wspólny prefiks zestawu ścieżek można uzyskać, pobierając wszystkie prefiksy każdej ścieżki (z PurePath.parents()
), biorąc przecięcie wszystkich tych zestawów nadrzędnych i wybierając najdłuższy wspólny prefiks.
PPPPPS : Python 3.5 wprowadził poprawne rozwiązanie tego pytania :,os.path.commonpath()
które zwraca prawidłową ścieżkę.
commonprefix
, ponieważ np. Wspólny prefiks for/usr/var/log
i/usr/var2/log
jest zwracany jako/usr/var
- co prawdopodobnie nie jest tym, czego można się spodziewać. (Możliwe jest również zwrócenie ścieżek, które nie są prawidłowymi katalogami.)['/usr/var1/log/', '/usr/var2/log/']
?os.path.relpath
:Tak więc, jeśli ścieżka względna zaczyna się od
'..'
- oznacza to, że druga ścieżka nie jest potomkiem pierwszej ścieżki.W Pythonie3 możesz użyć
PurePath.relative_to
:źródło
os.pardir
jest bardziej niezawodne niż sprawdzanie..
(uzgodniono, nie ma jednak wielu innych konwencji).os.relpath
silniejszy, ponieważ obsługuje..
iPurePath.relative_to()
nie obsługuje ? Czy coś mi brakuje?Inną opcją jest
źródło
os.pardir
przed dwiema możliwymi wynikowymi ścieżkami względnymi).Opis sugestii jme przy użyciu pathlib w Pythonie 3.
źródło
dir1.relative_to(dir2)
da PosixPath ('.'), Jeśli są takie same. Kiedy używaszif dir2 in dir1.parents
, wyklucza przypadek tożsamości. Jeśli ktoś porównuje ścieżki i chce uruchomić,relative_to()
jeśli są one zgodne ze ścieżkami, lepszym rozwiązaniem może byćif dir2 in (dir1 / 'x').parents
lubif dir2 in dir1.parents or dir2 == dir1
. Następnie uwzględniono wszystkie przypadki zgodności ścieżek.Czysty Python2 bez dep:
źródło
cwd
ipath
są takie same. należy najpierw sprawdzić, czy te dwa są takie same i zwrot albo""
albo"."
Edycja: Zobacz odpowiedź jme na najlepszy sposób z Python3.
Korzystając z pathlib, masz następujące rozwiązanie:
Powiedzmy, że chcemy sprawdzić, czy
son
jest potomkiemparent
i oba sąPath
obiektami. Możemy uzyskać listę części ścieżki za pomocąlist(parent.parts)
. Następnie po prostu sprawdzamy, czy początek syna jest równy liście segmentów rodzica.Jeśli chcesz zdobyć pozostałą część, możesz to zrobić
Jest to ciąg znaków, ale można go oczywiście użyć jako konstruktora innego obiektu Path.
źródło
parent in son.parents
, a jeśli tak, to resztę zdobądźson.relative_to(parent)
.