在本文的开头我们提出这样一个问题:
已知 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 看作两条 “河流”.
由于它们来自于同一个盘符, 可认为它们有同一个源头. 那么河流的情况 只存在 以下三种:
- a 和 b 是两条支流, 它们有一个交汇点 s (如图1)
- a 和 b 同属于一条河流, 互为 “上下游” 关系 (如图2)
- b 和 a 同属于一条河流, 互为 “上下游” 关系 (如图3)
这三种情况涵盖了当前问题中的所有 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