Hi,
Datei-finder (oder Filefinder) ist ein Modul zum POSIX-find ähnlichem finden von Dateien (in kurzform: datei-suchmaschine).
Davon gibt es zwei varianten: Eine rekursive*, und eine non-rekursive Variante.
Hier gehts zum Skript.
*: bedeutet, dass ich dafür os.walk() verwende, was leider ultra-rekursiv ist.
Datei-finder
Der Anspruch ist gewagt. POSIX-find kann weitaus mehr als Dateien gegen reguläre Ausdrücke prüfen.
Die Implementierung ist imho nicht ganz gelungen. Wieso setzt Du nicht einfach ein "re.compile()"-Objekt als "pattern" voraus, sondern baust letztlich die Signatur von "re.compile()" nach? Das Kompilieren des regulären Ausdrucks wäre auch performanter.
Außerdem wäre "re.search()" wohl sinnvoller als "re.match()". Schließlich möchte man meistens einfach nur irgendein Stück des Dateinamens prüfen, und um das Verhalten von "re.match()" zu erreichen, ist es genug, einfach "^" for das Muster zu setzen.
Zudem sind diese Funktionen geradezu prädestiniert für den Einsatz von Generatoren.
Die Rekursivität dagegen ist eigentlich ziemlich egal. Welches Dateisystem hat schon tausend Ebenen.
Die Implementierung ist imho nicht ganz gelungen. Wieso setzt Du nicht einfach ein "re.compile()"-Objekt als "pattern" voraus, sondern baust letztlich die Signatur von "re.compile()" nach? Das Kompilieren des regulären Ausdrucks wäre auch performanter.
Außerdem wäre "re.search()" wohl sinnvoller als "re.match()". Schließlich möchte man meistens einfach nur irgendein Stück des Dateinamens prüfen, und um das Verhalten von "re.match()" zu erreichen, ist es genug, einfach "^" for das Muster zu setzen.
Zudem sind diese Funktionen geradezu prädestiniert für den Einsatz von Generatoren.
Die Rekursivität dagegen ist eigentlich ziemlich egal. Welches Dateisystem hat schon tausend Ebenen.
Ja.. natürlich kann es das Das war auch mehr als vergleich gemeint (ein schlechter, zugegebenermassen).lunar hat geschrieben:Der Anspruch ist gewagt. POSIX-find kann weitaus mehr als Dateien gegen reguläre Ausdrücke prüfen.
Okay, umgesetzt, siehe hier. danke für den hinweisDie Implementierung ist imho nicht ganz gelungen. Wieso setzt Du nicht einfach ein "re.compile()"-Objekt als "pattern" voraus, sondern baust letztlich die Signatur von "re.compile()" nach? Das Kompilieren des regulären Ausdrucks wäre auch performanter.
Außerdem wäre "re.search()" wohl sinnvoller als "re.match()". Schließlich möchte man meistens einfach nur irgendein Stück des Dateinamens prüfen, und um das Verhalten von "re.match()" zu erreichen, ist es
genug, einfach "^" for das Muster zu setzen.
Zudem sind diese Funktionen geradezu prädestiniert für den Einsatz von Generatoren.
Ich hätte halt eine Funktion mit variabler rekursion irgendwie praktisch(er) gefunden... vielleicht bau ich sowas ja ein, wenn ich rausfind wieDie Rekursivität dagegen ist eigentlich ziemlich egal. Welches Dateisystem hat schon tausend Ebenen.
Ach so. In diesem Fall musst Du "os.walk()" neu implementieren, und die Rekursionstiefe zählen.
Aufgefallen ist mir noch die völlig unsinnige Ausnahmebehandlung. Wieso fängst Du die Ausnahmen ab, nur um sie dann neu zu verpacken? Lass die Ausnahmebehandlung einfach sein, dass ist Sache des Aufrufers. Zumal Du "re.error" an der völlig falschen Stelle abfängst, der Fehler wird bereits bei "re.compile()" ausgelöst.
Apropos "re.compile()": Wenn Du das Muster kompilierst, dann kannst Du auch gleich die Methoden dieses Exemplars verwenden "re.search()" ist dann "repattern.search()".
Allgemein aber würde ich "fileinfo()" komplett streichen. Die Auswahl ist willkürlich und realitätsfern (auf Lesbarkeit testet man durch das Öffnen der Datei). Reiche einfach den absoluten Dateinamen nach oben durch, dann kann der Aufrufer die relevanten Metadaten mittels "os.path.*" trivialerweise selbst abfragen.
Der triviale Rest der Funktion sieht dann so aus:
Aufgefallen ist mir noch die völlig unsinnige Ausnahmebehandlung. Wieso fängst Du die Ausnahmen ab, nur um sie dann neu zu verpacken? Lass die Ausnahmebehandlung einfach sein, dass ist Sache des Aufrufers. Zumal Du "re.error" an der völlig falschen Stelle abfängst, der Fehler wird bereits bei "re.compile()" ausgelöst.
Apropos "re.compile()": Wenn Du das Muster kompilierst, dann kannst Du auch gleich die Methoden dieses Exemplars verwenden "re.search()" ist dann "repattern.search()".
Allgemein aber würde ich "fileinfo()" komplett streichen. Die Auswahl ist willkürlich und realitätsfern (auf Lesbarkeit testet man durch das Öffnen der Datei). Reiche einfach den absoluten Dateinamen nach oben durch, dann kann der Aufrufer die relevanten Metadaten mittels "os.path.*" trivialerweise selbst abfragen.
Der triviale Rest der Funktion sieht dann so aus:
Code: Alles auswählen
def find(pattern, directory, searchdirs=True):
for filename in os.listdir(directory):
fullpath = os.path.join(directory, filename)
try:
if (not os.path.isdir(fullpath) or searchdirs):
if pattern.search(filename):
yield fullpath
Das meinte ich damit ... Das werd ich die nächsten tage versuchen.lunar hat geschrieben:Ach so. In diesem Fall musst Du "os.walk()" neu implementieren, und die Rekursionstiefe zählen.
Das mit der Ausnahme-behandlung passiert, wenn man gedankenlos text hind-und-her kopiertAufgefallen ist mir noch die völlig unsinnige Ausnahmebehandlung. Wieso fängst Du die Ausnahmen ab, nur um sie dann neu zu verpacken? Lass die Ausnahmebehandlung einfach sein, dass ist Sache des Aufrufers. Zumal Du "re.error" an der völlig falschen Stelle abfängst, der Fehler wird bereits bei "re.compile()" ausgelöst.
Apropos "re.compile()": Wenn Du das Muster kompilierst, dann kannst Du auch gleich die Methoden dieses Exemplars verwenden "re.search()" ist dann "repattern.search()".
Die sache RePatternObj.search() wusst ich nicht - ist beides in rev 3db445 gefixt.
Da stimm ich zu. Ist in der aktuellen revision auch nichtmehr vorhandenAllgemein aber würde ich "fileinfo()" komplett streichen. Die Auswahl ist willkürlich und realitätsfern (auf Lesbarkeit testet man durch das Öffnen der Datei). Reiche einfach den absoluten Dateinamen nach oben durch, dann kann der Aufrufer die relevanten Metadaten mittels "os.path.*" trivialerweise selbst abfragen.
Abgesehen davon dass du ein try-except block anfängst aber nicht beendest, wird das pattern an keiner stelle kompiliert (ich vermute mal dass du davon ausgehst dass der user das kompilat selbst übergeben soll). Ich hab das zum teil übernommen, nur wird in meiner Funktion das kompilat selbstständig erstellst, darum muss sich der User keine gedanken mehr machen müssen.Der triviale Rest der Funktion sieht dann so aus:Code: Alles auswählen
def find(pattern, directory, searchdirs=True): for filename in os.listdir(directory): fullpath = os.path.join(directory, filename) try: if (not os.path.isdir(fullpath) or searchdirs): if pattern.search(filename): yield fullpath
In "compile_pattern" erstellst Du immer noch Deinen eigenen RegexError. Warum? Der Nutzer sollte einfach direkt "re.error()" abfangen. "re" muss sowieso importiert werden, um an die Konstanten für die Flags zu gelangen.
fix'dlunar hat geschrieben:In "compile_pattern" erstellst Du immer noch Deinen eigenen RegexError. Warum? Der Nutzer sollte einfach direkt "re.error()" abfangen. "re" muss sowieso importiert werden, um an die Konstanten für die Flags zu gelangen.
Ich hab jetzt sowas wie os.walk() mit suchtiefen-begrenzung, bin mir nur nicht sicher, ob das auch wirklich funktioniert (oder besser gesagt, ob es vielleicht fehler gibt die ich übersehen hab):
Code: Alles auswählen
import os
def walk(folder, limit, depth=0):
if depth > limit:
return
for filename in os.listdir(folder):
fullpath = os.path.join(folder, filename)
if os.path.isdir(fullpath):
yield fullpath
for item in walk(fullpath, limit, depth + 1):
yield item
else:
yield fullpath