454 Stimmen

Umwandeln Sie eine Zeichenfolge in einen gültigen Dateinamen?

Ich habe einen String, den ich als Dateinamen verwenden möchte, daher möchte ich alle Zeichen entfernen, die in Dateinamen nicht erlaubt wären, mit Python.

Ich wäre lieber streng als nachlässig, also möchte ich nur Buchstaben, Zahlen und eine kleine Menge anderer Zeichen wie "_-.() " behalten. Was ist die eleganteste Lösung?

Der Dateiname muss auf mehreren Betriebssystemen gültig sein (Windows, Linux und Mac OS) - es handelt sich um eine MP3-Datei in meiner Bibliothek mit dem Songtitel als Dateiname und wird zwischen 3 Maschinen gemeinsam genutzt und gesichert.

35 Stimmen

Sollte dies nicht in das os.path-Modul integriert sein?

5 Stimmen

Vielleicht, obwohl ihr Anwendungsfall einen einzigen sicheren Pfad über alle Plattformen erfordern würde, nicht nur die aktuelle, wofür das Betriebssystem nicht konzipiert ist, um damit umzugehen.

6 Stimmen

Um den obigen Kommentar zu erweitern: Das aktuelle Design von os.path lädt tatsächlich je nach Betriebssystem eine andere Bibliothek (siehe die zweite Notiz in der Dokumentation). Wenn eine Quoting-Funktion in os.path implementiert wäre, könnte sie nur das Zeichenfolge für POSIX-Sicherheit quoten, wenn sie auf einem POSIX-System ausgeführt wird, oder für Windows-Sicherheit, wenn sie auf Windows ausgeführt wird. Der resultierende Dateiname wäre nicht unbedingt gültig für sowohl Windows als auch POSIX, was die Frage verlangt.

9voto

Ich weiß, dass es viele Antworten gibt, aber sie beruhen meistens auf regulären Ausdrücken oder externen Modulen, daher möchte ich meine eigene Antwort einbringen. Eine reine Python-Funktion, kein externes Modul erforderlich, kein regulärer Ausdruck verwendet. Mein Ansatz besteht nicht darin, ungültige Zeichen zu bereinigen, sondern nur gültige zuzulassen.

def normalizefilename(fn):
    validchars = "-_.() "
    out = ""
    for c in fn:
      if str.isalpha(c) or str.isdigit(c) or (c in validchars):
        out += c
      else:
        out += "_"
    return out    

Wenn Sie möchten, können Sie Ihre eigenen gültigen Zeichen zur validchars-Variablen am Anfang hinzufügen, wie z.B. Ihre nationalen Buchstaben, die im englischen Alphabet nicht existieren. Das ist etwas, was Sie vielleicht wollen oder auch nicht wollen: Einige Dateisysteme, die nicht auf UTF-8 basieren, könnten immer noch Probleme mit nicht-ASCII-Zeichen haben.

Diese Funktion dient dazu, die Gültigkeit eines einzelnen Dateinamens zu testen. Sie wird die Pfadtrennzeichen durch _ ersetzen, da sie sie als ungültige Zeichen betrachtet. Wenn Sie das hinzufügen möchten, ist es einfach, das if zu ändern, um den Betriebssystem-Pfadseparator einzuschließen.

9voto

Stavros Punkte 90

Wenn es Ihnen nichts ausmacht, ein Paket zu installieren, könnte dies nützlich sein: https://pypi.org/project/pathvalidate/

Von https://pypi.org/project/pathvalidate/#sanitize-a-filename:

from pathvalidate import sanitize_filename

fname = "fi:l*e/p\"a?t>h|.t {sanitize_filename(fname)}\n")
fname = "\0_a*b:ce%f/(g)h+i_0.txt"
print(f"{fname} -> {sanitize_filename(fname)}\n")

Output

fi:l*e/p"a?t>h|.t filepath.txt
_a*b:ce%f/(g)h+i_0.txt -> _abcde%f(g)h+i_0.txt

0 Stimmen

Dies ist eine sehr saubere Lösung

7voto

gx. Punkte 393

Sie könnten die re.sub() Methode verwenden, um alles außer "dateiartigem" zu ersetzen. Aber tatsächlich könnte jedes Zeichen gültig sein; daher gibt es keine vordefinierten Funktionen (soweit ich weiß), um dies zu erledigen.

import re

str = "File!name?.txt"
f = open(os.path.join("/tmp", re.sub('[^-a-zA-Z0-9_.() ]+', '', str))

Würde zu einem Dateihandle /tmp/filename.txt führen.

5 Stimmen

Sie müssen den Bindestrich als ersten im Gruppenmacher setzen, damit er nicht als Bereich erscheint. re.sub('[^-a-zA-Z0-9_.() ]+', '', str)

0 Stimmen

Hat Probleme mit Leerzeichen am Anfang und Ende eines Dateinamens, daher wurde das Regex zu [^-a-zA-Z0-9_.() ]+|^\s+|\s+$ geändert. Dies ist für den Fall, dass jemand anderes auf dieses Problem stößt.

7voto

therealmarv Punkte 3602

Ich mochte den Python-Slugify-Ansatz hier, aber er hat auch Punkte entfernt, was nicht erwünscht war. Also habe ich ihn optimiert, um auf diese Weise einen sauberen Dateinamen auf s3 hochzuladen:

pip install python-slugify

Beispielcode:

s = 'Very / Unsafe / file\nname hähä \n\r .txt'
clean_basename = slugify(os.path.splitext(s)[0])
clean_extension = slugify(os.path.splitext(s)[1][1:])
if clean_extension:
    clean_filename = '{}.{}'.format(clean_basename, clean_extension)
elif clean_basename:
    clean_filename = clean_basename
else:
    clean_filename = 'none' # nur unerwünschte Zeichen

Output:

>>> clean_filename
'very-unsafe-file-name-haha.txt'

Dies ist so ausfallsicher, es funktioniert mit Dateinamen ohne Erweiterung und sogar mit Dateinamen, die nur unerwünschte Zeichen enthalten (das Ergebnis ist hier none).

1 Stimmen

Ich mag das, erfinde das Rad nicht neu, importiere nicht das gesamte Django-Framework, wenn du es nicht brauchst, füge den Code nicht direkt ein, wenn du ihn in Zukunft nicht pflegen wirst, und der generierte String versucht, ähnliche Buchstaben durch sichere zu ersetzen, sodass der neue String einfacher zu lesen ist.

3 Stimmen

Um Unterstriche anstelle von Bindestrichen zu verwenden: name=slugify(s, separator='_')

6voto

karlcow Punkte 6879

Aber du musst vorsichtig sein. Es wird nicht klar gesagt in deinem Intro, ob du nur die lateinische Sprache betrachtest. Einige Wörter können bedeutungslos werden oder eine andere Bedeutung erhalten, wenn du sie nur mit ASCII-Zeichen bereinigst.

Stell dir vor, du hast "forêt poésie" (Waldpoesie), deine Säuberung könnte "fort-posie" (stark + etwas Bedeutungsloses) ergeben.

Schlimmer noch, wenn du mit chinesischen Zeichen umgehen musst.

"" dein System könnte am Ende "---" machen, was dazu verdammt ist, nach einer Weile zu scheitern und nicht sehr hilfreich ist. Wenn du also nur mit Dateien arbeitest, würde ich empfehlen, sie entweder als eine generische Kette zu bezeichnen, die du steuerst, oder die Zeichen so zu belassen, wie sie sind. Für URIs gilt ungefähr das gleiche.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X