os.path.commonprefix () dan os.path.relpath () adalah teman Anda:
>>> 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
'/'
Anda dapat menguji apakah awalan umum adalah salah satu jalur, yaitu jika salah satu jalur adalah leluhur yang sama:
paths = […, …, …]
common_prefix = os.path.commonprefix(list_of_paths)
if common_prefix in paths:
…
Anda kemudian dapat menemukan jalur relatif:
relative_paths = [os.path.relpath(path, common_prefix) for path in paths]
Anda bahkan dapat menangani lebih dari dua jalur, dengan metode ini, dan menguji apakah semua jalur di bawah salah satunya.
PS : tergantung pada bagaimana jalan Anda terlihat, Anda mungkin ingin melakukan normalisasi terlebih dahulu (ini berguna dalam situasi di mana orang tidak tahu apakah selalu berakhir dengan '/' atau tidak, atau jika beberapa jalur relatif). Fungsi yang relevan termasuk os.path.abspath () dan os.path.normpath () .
PPS : seperti yang disebutkan Peter Briggs dalam komentar, pendekatan sederhana yang dijelaskan di atas dapat gagal:
>>> os.path.commonprefix(['/usr/var', '/usr/var2/log'])
'/usr/var'
meskipun /usr/var
adalah bukan awalan umum dari jalur. Memaksa semua jalur diakhiri dengan '/' sebelum memanggil commonprefix()
memecahkan masalah (spesifik) ini.
PPPS : seperti yang disebutkan bluenote10, menambahkan garis miring tidak menyelesaikan masalah umum. Berikut adalah pertanyaan lanjutannya: Bagaimana cara menghindari kesalahan dari os.path.commonprefix Python?
PPPPS : dimulai dengan Python 3.4, kami memiliki pathlib , modul yang menyediakan lingkungan manipulasi jalur yang lebih waras. Saya kira awalan umum dari satu set lintasan dapat diperoleh dengan mendapatkan semua awalan dari setiap lintasan (dengan PurePath.parents()
), mengambil persimpangan dari semua set induk ini, dan memilih awalan umum terpanjang.
PPPPPS : Python 3.5 memperkenalkan solusi yang tepat untuk pertanyaan ini :,os.path.commonpath()
yang mengembalikan jalur yang valid.
commonprefix
, misalnya awalan umum untuk/usr/var/log
dan/usr/var2/log
dikembalikan sebagai/usr/var
- yang mungkin bukan yang Anda harapkan. (Mungkin juga untuk mengembalikan jalur yang bukan direktori yang valid.)['/usr/var1/log/', '/usr/var2/log/']
?os.path.relpath
:Jadi, jika jalur relatif dimulai dengan
'..'
- itu berarti bahwa jalur kedua bukan turunan dari jalur pertama.Di Python3 Anda dapat menggunakan
PurePath.relative_to
:sumber
os.pardir
lebih kuat daripada memeriksa..
(disepakati, tidak ada banyak konvensi lain).os.relpath
lebih kuat karena ia menangani..
danPurePath.relative_to()
tidak? Apakah saya melewatkan sesuatu?Pilihan lainnya adalah
sumber
os.pardir
di depan dua jalur relatif yang dihasilkan, meskipun).Penulisan saran jme, menggunakan pathlib, dengan Python 3.
sumber
dir1.relative_to(dir2)
akan memberikan PosixPath ('.') Jika mereka sama. Ketika Anda menggunakanif dir2 in dir1.parents
maka tidak termasuk kasus identitas. Jika seseorang membandingkan Paths dan ingin dijalankanrelative_to()
jika mereka kompatibel dengan path, solusi yang lebih baik mungkinif dir2 in (dir1 / 'x').parents
atauif dir2 in dir1.parents or dir2 == dir1
. Kemudian semua kasus kompatibilitas jalur tercakup.Python2 murni tanpa dep:
sumber
cwd
danpath
sama. itu harus memeriksa dulu apakah keduanya sama dan mengembalikan salah satu""
atau"."
Sunting: Lihat jawaban jme untuk cara terbaik dengan Python3.
Menggunakan pathlib, Anda memiliki solusi berikut:
Katakanlah kita ingin memeriksa apakah
son
keturunannyaparent
, dan keduanya adalahPath
objek. Kita bisa mendapatkan daftar bagian - bagian di jalan denganlist(parent.parts)
. Kemudian, kami hanya memeriksa bahwa permulaan anak laki-laki sama dengan daftar segmen orang tua.Jika Anda ingin mendapatkan bagian yang tersisa, Anda bisa melakukannya
Ini adalah string, tetapi tentu saja Anda dapat menggunakannya sebagai konstruktor dari objek Path lainnya.
sumber
parent in son.parents
, dan jika ya, dapatkan sisanyason.relative_to(parent)
.