Удаление первой папки в пути
У меня есть путь, который выглядит как
/First/Second/Third/Fourth/Fifth
и я хотел бы удалить из него First
, получив
Second/Third/Fourth/Fifth
Единственная идея, которую я мог придумать, - это использовать рекурсивно os.path.split
, но это не кажется оптимальным. Есть ли лучшее решение?
Ответы
Ответ 1
На самом деле в модуле os.path
ничего os.path
для этого. Время от времени кто-то предлагает создать функцию splitall
которая возвращает список (или итератор) всех компонентов, но он никогда не набирал достаточной тяги.
Отчасти это происходит потому, что каждый раз, когда кто-либо предлагал добавить новую функциональность в os.path
, он вновь зажигал давнюю неудовлетворенность общим дизайном библиотеки, что приводило к тому, что кто-то предлагал новый, более похожий на OO, API для путей к устарела ОС, неуклюжий 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.sep
путями или с системами с буквами дисков, и...
Или вы можете просто обернуть свой рекурсивный os.path.split
. Что именно является "неоптимальным" в этом после того, как вы завершили это? Это может быть немного медленнее, но мы говорим здесь наносекунды, на много порядков быстрее, чем даже вызывая stat
для файла. У вас будут проблемы глубины рекурсии, если у вас есть файловая система с глубиной 1000 каталогов, но вы когда-нибудь видели такую? (Если это так, вы всегда можете превратить его в цикл…) Требуется несколько минут, чтобы завершить его и написать хорошие модульные тесты, но это то, что вы просто делаете один раз и больше никогда не беспокоитесь. Так что, если честно, если вы не хотите использовать pathlib
, я бы так и сделал.
Ответ 2
Немного похоже на другой ответ, воспользовавшись os.path:
os.path.join(*(x.split(os.path.sep)[2:]))
... если ваша строка начинается с разделителя.
Ответ 3
Простой подход
a = '/First/Second/Third/Fourth/Fifth'
"/".join(a.strip("/").split('/')[1:])
выход:
Second/Third/Fourth/Fifth
В этом коде выше я разбил строку. затем присоединился, оставив 1-й элемент
Использование itertools.dropwhile
:
>>> a = '/First/Second/Third/Fourth/Fifth'
>>> "".join(list(itertools.dropwhile(str.isalnum, a.strip("/"))[1:])
'Second/Third/Fourth/Fifth'
Ответ 4
Я смотрел, если есть собственный способ сделать это, но, похоже, это не так.
Я знаю, что эта тема старая, но это то, что я сделал, чтобы получить лучшее решение:
В основном два подхода: использование 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 секунды ---
* Удаление char "/" в строке 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", чтобы проверить, начинается ли путь с имени файла, он был в два раза быстрее первого метода.
Вкратце: каждый метод имеет pro и con. Если вы абсолютно уверены в папке, которую хотите удалить, используйте метод два, в противном случае я рекомендую использовать метод 1, о котором люди упоминали ранее.