Hier sollten alle möglichen Probleme abgedeckt sein. Es behandelt alle Arten von Problemen für Sie, einschließlich (aber nicht beschränkt auf) Zeichenersetzungen.
Funktioniert auf Windows, *nix und fast jedem anderen Dateisystem. Erlaubt nur druckbare Zeichen.
def txt2filename(txt, chr_set='normal'):
"""Konvertiert txt in einen gültigen Windows/*nix Dateinamen nur mit druckbaren Zeichen.
args:
txt: Der zu konvertierende String.
chr_set: 'normal', 'universal' oder 'inclusive'.
'universal': ' -.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
'normal': Jedes druckbare Zeichen außer denen, die auf Windows/*nix nicht erlaubt sind.
'extended': Alle 'normalen' Zeichen plus die erweiterten Zeichen ASCII-Codes 128-255
"""
FILLER = '-'
# Schritt 1: Ausgeschlossene Zeichen entfernen.
if chr_set == 'universal':
# Suchen in einem Satz ist O(n) gegenüber O(n * x) für einen String.
printables = set(' -.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz')
else:
if chr_set == 'normal':
max_chr = 127
elif chr_set == 'extended':
max_chr = 256
else:
raise ValueError(f'Das chr_set-Argument kann normal, erweitert oder universal sein; nicht {chr_set=}')
EXCLUDED_CHRS = set(r'<>:"/\|?*') # Verbotene Zeichen in Windows-Dateinamen.
EXCLUDED_CHRS.update(chr(127)) # DEL (nicht druckbar).
printables = set(chr(x)
for x in range(32, max_chr)
if chr(x) not in EXCLUDED_CHRS)
result = ''.join(x if x in printables else FILLER # Nur druckbare Zeichen erlauben.
for x in txt)
# Schritt 2: Gerätenamen, '.' und '..' sind ungültige Dateinamen in Windows.
DEVICE_NAMES = 'CON,PRN,AUX,NUL,COM1,COM2,COM3,COM4,' \
'COM5,COM6,COM7,COM8,COM9,LPT1,LPT2,' \
'LPT3,LPT4,LPT5,LPT6,LPT7,LPT8,LPT9,' \
'CONIN$,CONOUT$,..,.'.split() # Diese Liste ist eine O(n)-Operation.
if result in DEVICE_NAMES:
result = f'-{result}-'
# Schritt 3: Maximale Dateinamenlänge beträgt 255 Byte in Windows und Linux (andere *nix-Varianten können längere Namen zulassen).
result = result[:255]
# Schritt 4: Windows erlaubt keine Dateinamen, die mit '.' oder ' ' enden oder mit ' ' beginnen.
result = re.sub(r'^[. ]', FILLER, result)
result = re.sub(r' $', FILLER, result)
return result
Diese Lösung benötigt keine externen Bibliotheken. Sie substituiert auch nicht druckbare Dateinamen, weil sie nicht immer einfach zu handhaben sind.
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 inos.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.0 Stimmen
Es ist einfach genug, die
Pfad
-Funktionen für ein anderes Betriebssystem zu verwenden. Verwenden Sie beispielsweise auf Uniximport ntpath; ntpath.abspath("a.txt")
, um den absoluten Pfad einer Datei in einem (hypothetischen) Windows-Dateisystem zu erhalten. Oder verwenden Sieposixpath
für POSIX-Systeme (Linux, Mac OS).