有没有一种聪明的方法在Python中合并重叠的路径?

9

假设我有两个路径名: headtail。它们可以与任意数量的片段重叠。如果它们没有重叠,我想正常地将它们连接起来。如果它们重叠,我想检测到共同部分并相应地组合它们。更具体地说:如果名称中存在重复,我希望尽可能找到最长的重叠部分。例如:

"/root/d1/d2/d1/d2" + "d2/d1/d2/file.txt" == "/root/d1/d2/d1/d2/file.txt"
and not "/root/d1/d2/d1/d2/d1/d2/file.txt"

有没有现成的库函数可以用来处理这种情况,还是我必须自己实现一个?

这是在Django中吗?还是只是Python? - WakeskaterX
这些路径是否在运行代码的同一台机器上? - Rcynic
一个程序员相关的问题:是否总是从/root开始?如果两个都是 d1/d2,结果应该是什么? - miraculixx
不要使用Django,只用Python;不一定是同一台机器;不一定以/root开头。 - ardabro
4个回答

3
你可以在join函数中使用列表推导式:
>>> p1="/root/d1/d2/d1/d2"
>>> p2="d2/d1/d2/file.txt"
>>> p1+'/'+'/'.join([i for i in p2.split('/') if i not in p1.split('/')])
'/root/d1/d2/d1/d2/file.txt'

如果第二个路径只是基础名称与第一个路径不同,您可以使用os.path.basename获取基础名称并将其连接到p1中:

>>> import os
>>> p1+'/'+os.path.basename(p2)
'/root/d1/d2/d1/d2/file.txt'

成功了!你真是个天才! - ardabro
3
这个回答很好,但如果p1="/root/d1/d2/d1/d2",p2="d2/d1/d2/d2/file.txt",那么最终的字符串将是"/root/d1/d2/d1/d2/file.txt",而不是"/root/d1/d2/d1/d2/d2/file.txt"。我的意思是,p2与p1共享的任何文件夹名称必须始终是唯一的,如果不是,则具有相同名称的其他文件夹将从not in p1.split("/")中删除。 - John Smith
1
对于以下代码无法正常工作: p1 = "/root/b/a" p2 = "a/b/file.txt" p1 + '/' + '/'.join([i for i in p2.split('/') if i not in p1.split('/')]) - Yuval Pruss

3

我建议您使用difflib.SequenceMatcher,然后再使用get_matching_blocks函数。

>>> p1, p2 = "/root/d1/d2/d1/d2","d2/d1/d2/file.txt"
>>> sm = difflib.SequenceMatcher(None,p1, p2)
>>> size = sm.get_matching_blocks()[0].size
>>> path = p1 + p2[size:]
>>> path
'/root/d1/d2/d1/d2/file.txt'

Ans一个通用解决方案

def join_overlapping_path(p1, p2):
    sm = difflib.SequenceMatcher(None,p1, p2)
    p1i, p2i, size = sm.get_matching_blocks()[0]
    if not p1i or not p2i: None
    p1, p2 = (p1, p2) if p2i == 0 else (p2, p1)
    size = sm.get_matching_blocks()[0].size
    return p1 + p2[size:]

执行

>>> join_overlapping_path(p1, p2)
'/root/d1/d2/d1/d2/file.txt'
>>> join_overlapping_path(p2, p1)
'/root/d1/d2/d1/d2/file.txt'

1
我认为这个有效:

p1 = "/root/d1/d2/d1/d2"
p2 = "d2/d1/d2/file.txt"

def find_joined_path(p1, p2):
    for i in range(len(p1)):
        if p1[i:] == p2[:len(p1) - i]:
            return p1[:i] + p2

print(find_joined_path(p1, p2))

请注意,这是一种适用于任何两个字符串的通用解决方案,因此可能没有针对文件路径专门设计的解决方案那么优化。

0

我刚刚来到这里寻找答案。希望它能帮助其他人。
以下是我在Nodejs中的实现方式

const path1 = '/root/user/name/code/website/'
const path2 = './website/index.js'

const arrOfDirectories = [...path1.split('/'), ...path2.split('/')] 
// ['', 'root', 'user', 'name', 'code', 'website', '', '.' 'website', 'index.js']

const arrOfUniqueDirectories = arrOfDirectories.filter((value, index, self) => self.indexOf(value) === index)
// ['', 'root', 'user', 'name', 'code', 'website', '', '.','index.js']

const jankyPath = arrOfUniqueDirectories.join('/')
// /root/user/name/code/website./index.js

const myPath = path.normalize(jankyPath)
// myPath = /root/user/name/code/website/index.js

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接