2014-11-03 9 views
15

Ich habe einen Weg, der Entfernen des ersten Ordner in einem Pfad

/First/Second/Third/Fourth/Fifth 

wie

aussieht und ich würde die First daraus entfernen mögen, so

Second/Third/Fourth/Fifth 

Die einzige Idee zu erhalten konnte ich kommen up mit rekursiv zu verwenden ist os.path.split, aber das scheint nicht optimal. Gibt es eine bessere Lösung?

Antwort

13

Es gibt wirklich nichts im os.path Modul, um dies zu tun. Hin und wieder schlägt jemand vor, eine splitall-Funktion zu erstellen, die eine Liste (oder Iterator) aller Komponenten zurückgibt, aber nie genug Zugkraft hat. Das liegt zum Teil daran, dass jedes Mal, wenn jemand einmal vorgeschlagen hat, neue Funktionen zu os.path hinzuzufügen, die lang anhaltende Unzufriedenheit mit dem allgemeinen Design der Bibliothek neu entfacht wurde, was dazu führte, dass jemand eine neue, mehr OO-ähnliche API vorschlug Pfade zu veraltet die os, clunky API. In 3.4, das ist schließlich passiert, mit pathlib. Und es hat bereits Funktionalität, die nicht in os.path war. Also:

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

Oder ... sind Sie sicher, dass Sie wirklich die erste Komponente entfernen möchten, anstatt dies zu tun?

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

Wenn Sie dies in 2,6-2,7 oder 3,2-3,3 tun müssen, gibt es eine backport of pathlib.

Natürlich können Sie die String-Manipulation verwenden, solange Sie den Pfad normalisieren und os.path.sep verwenden und sicherstellen, dass Sie die frechen Details mit nicht-absoluten Pfaden oder mit Systemen mit Laufwerksbuchstaben und ...

Oder Sie können einfach Ihre rekursive os.path.split einpacken. Was genau ist "nicht optimal" darüber, sobald Sie es einpacken? Es mag etwas langsamer sein, aber wir reden hier Nanosekunden, viele Größenordnungen schneller als sogar stat in einer Datei anzurufen. Es wird Probleme mit der Rekursionstiefe geben, wenn Sie ein Dateisystem haben, das 1000 Verzeichnisse tief hat, aber haben Sie jemals eines gesehen? (Wenn ja, können Sie es immer in eine Schleife verwandeln ...) Es dauert ein paar Minuten, um es zu beenden und gute Komponententests zu schreiben, aber das ist etwas, was Sie nur einmal tun und sich nie wieder sorgen. Also, ehrlich gesagt, wenn Sie nicht pathlib verwenden wollen, würde ich das tun.

+0

'pathlib' dosent kommen mit Python, müssen es installieren – Hackaholic

+0

Leistung weise Sie sind völlig richtig: Wir sprechen über Nanosekunden; es ist mehr ich versuche, den besten Weg zu lernen/andere Möglichkeiten, es zu tun – meto

+0

@Hackaholic: Wie die Antwort im Detail erklärt, kommt 'Pathlib' mit Python 3.4+, und Sie können den Backport für 2.6-2.7 oder 3.2-3.3 installieren . – abarnert

4

Ein einfacher Ansatz

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

Ausgang:

Second/Third/Fourth/Fifth 

In diesem obigen Code i die Zeichenfolge aufgeteilt haben. dann trat erste Element

Mit itertools.dropwhile verlassen:

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

Zuerst dachte ich, das würde nicht auf Pfaden funktionieren, die mit dem Pfadtrenner beginnen, weil du anscheinend das erste Zeichen aus der Zeichenkette entfernen willst, aber bei weiterer Überprüfung, was zählt das erste Zeichen, wenn du nur das erste Segment entfernst . +1, aber vielleicht etwas in der Antwort, die das sagt (oder vielleicht ein Kommentar von jemandem, dem du geholfen hast) – iLoveTux

+0

@iLoveTux hat es effizienter gemacht – Hackaholic

8

Ein bisschen wie eine andere Antwort, die Vorteile von os.path unter:

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

... Zeichenfolge unter der Annahme, mit einem Separator beginnt.

+1

Kannst du ein bisschen über die Verwendung des "*" hier erklären? – Luke

+0

@Luke Das * wird verwendet, um die Menge zu behandeln, die von '(x.split (os.path.sep) [2:])' als das Schlüsselwort '* args' erzeugt wird. Dies wird jedoch nicht funktionieren, da der Pfad zu kurz ist, da die Argumentliste komplett leer ist – asdf

1

Ich habe gesucht, ob es einen nativen Weg gab, es zu tun, aber es scheint, dass es nicht tut.

Ich weiß, dass dieses Thema alt ist, aber das ist, was ich getan habe, um mich zur besten Lösung zu bringen: Es gab zwei grundsätzlich zwei Ansätze: mit split() und len(). Beide mussten schneiden.

1) Unter Verwendung von 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)) 

Ergebnis: --- --- 0,420122861862 Sekunden lang

* Entfernen des char "/" in der Zeile new_path = "/" + "/".... hat die Leistung nicht zu sehr verbessert.

2) Mit len ​​(). Diese Methode funktioniert nur, wenn Sie den Ordner zur Verfügung stellen, wenn Sie

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)) 

Ergebnis entfernen möchten: --- ,199596166611 Sekunden ---

* Auch mit dem „if“ überprüfen Wenn der Pfad mit dem Dateinamen beginnt, war er doppelt so schnell wie die erste Methode.

Zusammenfassend: jede Methode hat ein Pro und Con. Wenn Sie absolut sicher sind, welchen Ordner Sie entfernen möchten, verwenden Sie Methode zwei, ansonsten empfehle ich, Methode 1 zu verwenden, die die Leute hier bereits erwähnt haben.

Verwandte Themen