두 절대 경로를 비교하여 상대 경로 가져오기
예를 들어, 저에게는 두 가지 절대적인 길이 있습니다.경로 중 하나가 가리키는 위치가 다른 경로의 후손인지 확인해야 합니다.사실이라면 조상으로부터 후손의 상대적인 경로를 알아내야 합니다.파이썬에서 이를 구현하는 좋은 방법은 무엇입니까?제가 혜택을 받을 수 있는 도서관이 있나요?
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]
이 방법을 사용하여 두 개 이상의 경로를 처리하고 모든 경로가 두 경로 중 하나 아래에 있는지 테스트할 수도 있습니다.
PS: 경로의 모양에 따라 먼저 정규화를 수행할 수 있습니다(항상 '/'로 끝나는지 여부를 알 수 없거나 일부 경로가 상대적인 경우에 유용합니다).관련 함수에는 os.path.abspath() 및 os.path.normpath()가 포함됩니다.
PPS: Peter Briggs가 코멘트에서 언급했듯이, 위에서 설명한 간단한 접근법은 실패할 수 있습니다.
>>> os.path.commonprefix(['/usr/var', '/usr/var2/log'])
'/usr/var'
그럼에도 불구하고./usr/var
경로의 일반 접두사가 아닙니다.호출하기 전에 모든 경로가 '/'로 끝나도록 강제하는 중commonprefix()
이 (특정) 문제를 해결합니다.
PPPS: 블루노트10에서 언급한 것처럼 슬래시를 추가한다고 해서 일반적인 문제가 해결되지는 않습니다.다음은 그의 후속 질문입니다.Python의 os.path.common 접두사의 오류를 피하는 방법은 무엇입니까?
PPPPS: Python 3.4부터, 우리는 더 깔끔한 경로 조작 환경을 제공하는 모듈인 pathlib을 가지고 있습니다.경로 집합의 공통 접두사는 각 경로의 모든 접두사를 가져와서(와) 이러한 모든 부모 집합의 교차점을 취하고 가장 긴 공통 접두사를 선택함으로써 얻을 수 있다고 생각합니다.
PPPPS: Python 3.5는 유효한 경로를 반환하는 이 질문에 적절한 솔루션을 도입했습니다.
현재 디렉터리 또는 선택적 시작점에서 상대 파일 경로를 경로로 반환합니다.
>>> from os.path import relpath
>>> relpath('/usr/var/log/', '/usr/var')
'log'
>>> relpath('/usr/var/log/', '/usr/var/sad/')
'../log'
따라서 상대 경로가 다음으로 시작하는 경우'..'
두 번째 경로가 첫 번째 경로의 하위가 아님을 의미합니다.
Python3에서는 다음을 사용할 수 있습니다.
Python 3.5.1 (default, Jan 22 2016, 08:54:32)
>>> from pathlib import Path
>>> Path('/usr/var/log').relative_to('/usr/var/log/')
PosixPath('.')
>>> Path('/usr/var/log').relative_to('/usr/var/')
PosixPath('log')
>>> Path('/usr/var/log').relative_to('/etc/')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/Cellar/python3/3.5.1/Frameworks/Python.framework/Versions/3.5/lib/python3.5/pathlib.py", line 851, in relative_to
.format(str(self), str(formatted)))
ValueError: '/usr/var/log' does not start with '/etc'
Python 3에서 pathlib을 사용한 jme의 제안에 대한 글입니다.
from pathlib import Path
parent = Path(r'/a/b')
son = Path(r'/a/b/c/d')
if parent in son.parents or parent==son:
print(son.relative_to(parent)) # returns Path object equivalent to 'c/d'
또 다른 옵션은
>>> print os.path.relpath('/usr/var/log/', '/usr/var')
log
dep이 없는 Pure Python2:
def relpath(cwd, path):
"""Create a relative path for path from cwd, if possible"""
if sys.platform == "win32":
cwd = cwd.lower()
path = path.lower()
_cwd = os.path.abspath(cwd).split(os.path.sep)
_path = os.path.abspath(path).split(os.path.sep)
eq_until_pos = None
for i in xrange(min(len(_cwd), len(_path))):
if _cwd[i] == _path[i]:
eq_until_pos = i
else:
break
if eq_until_pos is None:
return path
newpath = [".." for i in xrange(len(_cwd[eq_until_pos+1:]))]
newpath.extend(_path[eq_until_pos+1:])
return os.path.join(*newpath) if newpath else "."
편집 : Python3에서 가장 좋은 방법은 jme의 답변을 참고하세요.
pathlib을 사용하면 다음과 같은 해결책이 있습니다.
우리가 확인하고 싶다고 가정해 보겠습니다.son
는 의후니다의 입니다.parent
다 그리고 둘다다 둘▁and입니다.Path
물건들.다음을 통해 경로에 있는 부품의 목록을 얻을 수 있습니다.list(parent.parts)
그런 다음 아들의 시작이 부모의 세그먼트 목록과 동일한지 확인합니다.
>>> lparent = list(parent.parts)
>>> lson = list(son.parts)
>>> if lson[:len(lparent)] == lparent:
>>> ... #parent is a parent of son :)
나머지 부분을 받고 싶으면 그냥 하면 됩니다.
>>> ''.join(lson[len(lparent):])
문자열이지만 다른 경로 개체의 생성자로 사용할 수도 있습니다.
언급URL : https://stackoverflow.com/questions/7287996/get-relative-path-from-comparing-two-absolute-paths
'programing' 카테고리의 다른 글
Spring 5 Reactive에서의 HTTP 응답 예외 처리 (0) | 2023.06.21 |
---|---|
이 두 개의 고차 함수 정의 사이에 차이점이 있습니까? (0) | 2023.06.21 |
loadurl을 호출할 때 Android 웹 보기가 브라우저를 시작합니다. (0) | 2023.06.21 |
Firebase Cloud Messaging을 사용하여 장치를 장치 메시지로 보내는 방법은 무엇입니까? (0) | 2023.06.16 |
VBA를 사용하여 컴퓨터에서 사용 중인 십진수 기호 탐지 (0) | 2023.06.16 |