1. ホーム
  2. python

[解決済み] 2つの絶対パスを比較し、相対パスを取得する

2022-04-25 22:04:14

質問

例えば、2つの絶対パスがあるとします。一方のパスが参照している場所が、他方のパスの子孫であるかどうかを確認する必要があります。もしそれが本当なら、先祖からの子孫の相対パスを見つける必要がある。Pythonでこれを実装するための良い方法は何ですか?私が恩恵を受けることができる任意のライブラリ?

どのように解決するのですか?

os.path.commonprefix() os.path.relpath() が友達です。

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

このようにして、共通の接頭辞がパスのいずれかであるかどうか、つまりパスのいずれかが共通の祖先であるかどうかをテストすることができるのです。

paths = […, …, …]
common_prefix = os.path.commonprefix(list_of_paths)
if common_prefix in paths:
    …

そうすると、相対パスがわかります。

relative_paths = [os.path.relpath(path, common_prefix) for path in paths]

このメソッドで、2つ以上のパスを処理し、すべてのパスがそのうちの1つのパスの下にすべてあるかどうかをテストすることも可能です。

PS : パスがどのようなものかにもよりますが、最初に何らかの正規化を行っておくとよいでしょう (常に '/' で終わっているかどうかわからない場合や、パスの一部が相対パスである場合などに便利です)。 関連する関数は以下の通りです。 os.path.abspath() os.path.normpath() .

ピーピーエス : コメントでPeter Briggsが述べているように、上記のような単純なアプローチでは失敗することがあります。

>>> os.path.commonprefix(['/usr/var', '/usr/var2/log'])
'/usr/var'

とはいえ /usr/var ではない をパスの共通接頭辞とする。 を呼び出す前に、すべてのパスの末尾を '/' にすることを強制する。 commonprefix() は、この(特定の)問題を解決します。

PPPS : bluenote10 さんがおっしゃるように、スラッシュを追加しても一般的な問題は解決しません。以下は彼のフォローアップの質問です。 Python の os.path.commonprefix の誤りを回避する方法は?

PPPPS : Python 3.4 からは、次のようになります。 パスリブ より健全なパス操作の環境を提供するモジュールです。パスの集合の共通の接頭辞は、各パスの接頭辞をすべて取得することで得られると思うのですが、( PurePath.parents() ) を作成し、これらすべての親セットの交差点を取り、最も長い共通の接頭辞を選択します。

PPPPPS : Python 3.5では、この問題に対する適切な解答が導入されました。 os.path.commonpath() これは有効なパスを返します。