移除路径中的第一个文件夹

103 投票
5 回答
78424 浏览
提问于 2025-05-01 10:16

我有一个路径,长得像这样:

/First/Second/Third/Fourth/Fifth

我想把里面的 First 去掉,最终得到:

Second/Third/Fourth/Fifth

我想到的办法是用递归的方式来使用 os.path.split,但感觉这不是最好的方法。有没有更好的解决办法呢?

暂无标签

5 个回答

0

我在找有没有简单的方法来实现这个功能,但看起来没有。

我知道这个话题已经有点老了,但这是我找到的最佳解决方案:基本上有两种方法:使用split()和使用len()。这两种方法都需要用到切片。

1) 使用split()

import time

start_time = time.time()

path = "/folder1/folder2/folder3/file.zip"
for i in xrange(500000):
    new_path = "/" + "/".join(path.split("/")[2:])

print("--- %s seconds ---" % (time.time() - start_time))

结果:--- 0.420122861862秒 ---

*在new_path = "/" + "/"....这一行中去掉字符"/"并没有显著提高性能。

2) 使用len()。这种方法只有在你提供想要删除的文件夹时才有效

import time

start_time = time.time()

path = "/folder1/folder2/folder3/file.zip"
folder = "/folder1"
for i in xrange(500000):
    if path.startswith(folder):
        a = path[len(folder):]

print("--- %s seconds ---" % (time.time() - start_time))

结果:--- 0.199596166611秒 ---

*即使加上了检查路径是否以文件名开头的“if”条件,这种方法的速度还是比第一种快了两倍。

总结一下:每种方法都有优缺点。如果你非常确定想要删除的文件夹,使用第二种方法;否则,我建议使用第一种方法,之前有很多人提到过。

20

这里有一个简单的方法

a = '/First/Second/Third/Fourth/Fifth'
"/".join(a.strip("/").split('/')[1:])

输出结果:

Second/Third/Fourth/Fifth

在上面的代码中,我把字符串分开了,然后把第一个元素去掉,剩下的部分再连接起来。

使用 itertools.dropwhile

>>> a = '/First/Second/Third/Fourth/Fifth'
>>> "".join(list(itertools.dropwhile(str.isalnum, a.strip("/"))[1:])
'Second/Third/Fourth/Fifth'
22

你可以试试:

os.path.relpath(your_path, '/First')
26

这段话有点像其他的回答,利用了 os.path 这个模块:

os.path.join(*(x.split(os.path.sep)[2:]))

... 假设你的字符串是以一个分隔符开头的。

134

其实在 os.path 这个模块里并没有直接可以做到这个的功能。偶尔会有人提议创建一个 splitall 函数,能返回一个包含所有部分的列表(或者迭代器),但这个想法一直没有得到广泛支持。

部分原因是,每次有人建议在 os.path 中添加新功能时,都会引发对这个库设计的不满,导致有人提议用一个更面向对象的路径API来替代这个笨重的 os API。在3.4版本中,这个提议终于实现了,推出了 pathlib。而且它已经有了 os.path 中没有的功能。所以:

>>> import pathlib
>>> p = pathlib.Path('/First/Second/Third/Fourth/Fifth')
>>> p.parts[2:]
('Second', 'Third', 'Fourth', 'Fifth')
>>> pathlib.Path(*p.parts[2:])
PosixPath('Second/Third/Fourth/Fifth')

或者……你确定你真的想去掉第一个部分,而不是这样做吗?

>>> p.relative_to(*p.parts[:2])
PosixPath('Second/Third/Fourth/Fifth')

如果你需要在2.6-2.7或3.2-3.3版本中做到这一点,可以使用 pathlib的回溯版本

当然,你也可以使用字符串操作,只要你小心地规范化路径,使用 os.path.sep,并确保处理好一些麻烦的细节,比如非绝对路径或者带有驱动器字母的系统等等……

或者你可以把你的递归 os.path.split 封装起来。封装之后,究竟有什么地方是“不够优化”的呢?可能会稍微慢一点,但我们说的是纳秒级的差别,这比调用文件的 stat 快得多。如果你的文件系统有1000层目录,可能会遇到递归深度的问题,但你见过这样的文件系统吗?(如果见过,你总是可以把它改成循环的……)封装起来并写好单元测试只需要几分钟,但这只是一次性的事情,以后就不用再担心了。所以,老实说,如果你不想使用 pathlib,我会选择这样做。

撰写回答