轻松理解 python 相对路径计算

时间:2024-03-16 20:10:37

在本文的开头我们提出这样一个问题:

已知 a 和 b 两个绝对路径, 求 b 相对于 a 的相对路径.

这里我们加一个限制条件, a 和 b 来自于同一个盘符 (否则求相对路径就没有意义了), 示例如下:

a = 'D:/M/N/O/P/a.py'
b = 'D:/M/N/Q/b.py'

当然实际情况会比较复杂, 例如 a 的路径深度和 b 不一样, a 和 b 的岔开点的问题等.

现在我们换一种思路, 把 a 和 b 看作两条 “河流”.

由于它们来自于同一个盘符, 可认为它们有同一个源头. 那么河流的情况 只存在 以下三种:

  1. a 和 b 是两条支流, 它们有一个交汇点 s (如图1)
  2. a 和 b 同属于一条河流, 互为 “上下游” 关系 (如图2)
  3. b 和 a 同属于一条河流, 互为 “上下游” 关系 (如图3)

轻松理解 python 相对路径计算

这三种情况涵盖了当前问题中的所有 a 和 b 绝对路径的可能情形. 这三个情况的共同点是, 有一个相交的地方, 比如图1的 s 点, 图2的 a 点, 和图3的 b 点.

那么求相对路径的问题可以看作两个过程: 先从 a 回溯到交汇点, 再从交汇点流向 b.

回溯的计算, 可以获得 ‘…/’ 的数量.

顺流的计算, 可以获得从交汇点到 b 的路径.

这两个相加就是 b 相对于 a 的相对值了.

函数也非常简单, 表示如下:

def calculate_relative_path(a, b):
    """
    计算相对路径:
        已知两个绝对路径 a 和 b, 求 b 相对于 a 的相对路径.

	注:
		1. a 和 b 来自于同一个盘符
		2. 路径分隔符用正斜杠 "/"
    """
    
    a, b = a.split('/'), b.split('/')
    # a = 'D:/M/N/O/P/a.py' --> ['D:', 'M', 'N', 'O', 'P', 'a.py']
    # b = 'D:/M/N/Q/b.py' --> ['D:', 'M', 'N', 'Q', 'b.py']
    
    intersection = 0  # 交汇点位置
    
    for index in range(min(len(a), len(b))):
        m, n = a[index], b[index]
        if m != n:
            intersection = index  # --> 3
            break
    
    def backward():  # "溯流而上"
        return (len(a) - intersection - 1) * '../'
    	# (6 - 3 - 1) * '../' --> '../../'
    
    def forward():  # "顺流而下"
        return '/'.join(b[intersection:])
    	# ['D:', 'M', 'N', 'Q', 'b.py'] --> 'Q/b.py'
    
    out = backward() + forward()
    # '../../' + 'Q/b.py' --> '../../Q/b.py'
    return out