如何计算Python3中的根相对路径?

how to calculate root relative path in Python3?

任务是实现一个函数root_relative_path(root : str, path : str) -> str,它计算相对于根的相对路径,没有中间..超出root。例如,root_relative_path('/abc', '/../def') == '/abc/def'

这个问题不同于,因为在这种情况下,root_relative_path(root='/tmp/abc', path='/../def')应该return /tmp/abc/def而不是/tmp/def

import os.path

def root_relative_path(root : str, path : str) -> str:
    return (os.path.join(root,
        os.path.join(os.sep, os.path.normpath(path)).split(os.sep)[1:])))

我能够使用 posixpath 和 pathlib 模块的组合来实现您的 root_relative_path 功能。结果是

  • 平台无关(只要根路径对应当前平台即可)
  • 路径可以以 /./../
  • 开头
  • 并且将使用 normpath 函数涵盖的所有技术对路径进行规范化,其中包括解析 ..s.

from pathlib import Path
import posixpath

def root_relative_path(root : str, path : str) -> str:
    ''' Calculates the relative path with respect to the root. 
        Any ".."s in the relative path will be resolved, 
        but not in a way that would cause the relative path to go beyond the root. '''

    # posixpath.normpath doesn't work as expected if the path doesn't start with a slash, so we make sure it does
    if not path.startswith('/'):
        path = '/' + path

    # The normalization process includes resolving any ".."s
    # we're only using posixpath for the relative portion of the path, the outcome will still be platform independent
    path = posixpath.normpath(path)

    # Remove the beginning slash so that we're not trying to join two absolute paths
    path = path[1:]

    joined = Path(root) / path

    # Per the OPs requirements the result needed to be a string,
    # But if you're allowed to use Pathlib objects, you could just return joined without converting it to a string
    return str(joined)

这个怎么样:

from pathlib import Path

def get_relative_path(path_from: Path, path_to: Path) -> Path:
    """
    Calculate and return a relative path between the `path_from` and
    `path_to` paths. Both paths must be absolute paths!
    """
    if not (path_from.is_absolute() and path_to.is_absolute()):
        raise ValueError('One or both of the passed paths are not absolute.')
    items_from = path_from.parts
    items_to = path_to.parts
    while items_from[0] == items_to[0]:
        items_from = items_from[1:]
        items_to = items_to[1:]
    return Path(*('..' for x in range(1, len(items_from))), *items_to)