Bir dize geçerli bir dosya adına dönüştürülsün mü?


298

Dosya adı olarak kullanmak istediğim bir dize var, bu yüzden Python kullanarak dosya adlarında izin verilmeyecek tüm karakterleri kaldırmak istiyorum.

Aksi halde katı olmayı tercih ederim, bu yüzden diyelim ki sadece harfleri, rakamları ve diğer küçük karakter kümelerini tutmak istiyorum "_-.() ". En zarif çözüm nedir?

Dosya adının birden çok işletim sisteminde geçerli olması gerekir (Windows, Linux ve Mac OS) - kütüphanemde şarkı adı dosya adı olan bir MP3 dosyasıdır ve 3 makine arasında paylaşılır ve yedeklenir.


17
Bu os.path modülünün içine yerleştirilmemeli mi?
endolith

2
Belki de kullanım durumu , sadece mevcut olanı değil, tüm platformlarda güvenli olan tek bir yol gerektirse de, os.path'in işlemek için tasarlanmadığı bir şey.
javawizard

2
Yukarıdaki yorumu genişletmek için: mevcut tasarım os.pathaslında işletim sistemine bağlı olarak farklı bir kütüphane yükler (bkz . Belgelerdeki ikinci nota ). Bu nedenle, bir tırnak işlevi uygulanmışsa os.path, dize yalnızca bir POSIX sisteminde çalışırken POSIX güvenliği için veya pencerelerde çalışırken windows güvenliği için teklif verebilir. Sonuçta ortaya çıkan dosya adı, her iki pencerede ve sorunun sorulduğu POSIX için geçerli olmayabilir.
dshepherd

Yanıtlar:


164

Keyfi metinden nasıl bir "sülük" oluşturdukları için Django çerçevesine bakabilirsiniz . Bir bilgi URL ve dosya adı dostudur.

Django metin araçları bir işlevi tanımlar slugify(), bu muhtemelen bu tür şeyler için altın standarttır. Esasen, kodları aşağıdaki gibidir.

def slugify(value):
    """
    Normalizes string, converts to lowercase, removes non-alpha characters,
    and converts spaces to hyphens.
    """
    import unicodedata
    value = unicodedata.normalize('NFKD', value).encode('ascii', 'ignore')
    value = unicode(re.sub('[^\w\s-]', '', value).strip().lower())
    value = unicode(re.sub('[-\s]+', '-', value))
    # ...
    return value

Dahası da var, ama slugifikasyona değil, kaçmaya karşı çıktığı için dışarıda bıraktım.


11
Son satır şu şekilde olmalıdır: value = unicode (re.sub ('[- \ s] +', '-', değer))
Joseph Turian

1
Teşekkürler - Ben bir şey eksik olabilir, ama alıyorum: "normalize () argüman 2 unicode olmalı, str değil"
Alex Cook

msgstr "normalize () argüman 2". Anlamına gelir value. Değerin Unicode olması gerekiyorsa, bunun gerçekte Unicode olduğundan emin olmalısınız. Veya. Gerçek değeriniz aslında bir ASCII dizesi ise, unicode normalizasyonunu dışarıda bırakmak isteyebilirsiniz.
S.Lott

8
Herhangi birinin bu yaklaşımın olumlu yanını fark etmemesi durumunda, sadece alfa olmayan karakterleri kaldırmakla kalmaz, aynı zamanda önce iyi yedekleri bulmaya çalışır (NFKD normalizasyonu yoluyla), yani é e olur, üst simge 1 normal 1, vb. Teşekkürler
Michael Scott Cuthbert

48
slugifyFonksiyon taşındı için django / utils / text.py ve bu dosya da içeriyor get_valid_filenameişlevi.
Denilson Sá Maia

105

Bu beyaz liste yaklaşımı (yani yalnızca geçerli_karakterlerde mevcut olan karakterlere izin vermek), dosyaların biçimlendirilmesinde veya yasa dışı olan geçerli karakterlerin birleşiminde (".." gibi) sınırlar yoksa, örneğin söylediğiniz gibi çalışır Windows'ta geçerli olmadığını düşündüğüm ". txt" adlı bir dosya adına izin verir. Bu, boşluğu geçerli_karaklardan kaldırmaya çalıştığım ve hata durumunda bilinen bir geçerli dizginin başına eklediğim en basit yaklaşım olduğundan, diğer herhangi bir yaklaşımın Windows dosya adlandırma sınırlamaları ile nerede başa çıkabileceğine ve bu nedenle çok daha karmaşık.

>>> import string
>>> valid_chars = "-_.() %s%s" % (string.ascii_letters, string.digits)
>>> valid_chars
'-_.() abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
>>> filename = "This Is a (valid) - filename%$&$ .txt"
>>> ''.join(c for c in filename if c in valid_chars)
'This Is a (valid) - filename .txt'

7
valid_chars = frozenset(valid_chars)incitmezdi. Allchars'a uygulandığında 1,5 kat daha hızlıdır.
jfs

2
Uyarı: Bu, iki farklı dizeyi aynı dizeyle eşleştirir >>> import dize >>> valid_chars = "- . ()% S% s"% (string.ascii_letters, string.digits) >>> valid_chars '- . () abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 '>>> dosyaadı = "a.com/hello/world" >>>' '. katıl (geçerli_chartılarda c dosya adında c için)' a.com ">>> ''. katıl (dosya_adı için c, geçerli_karakterde c ise) 'a.comhelloworld' >>>
robert king

3
"CON"Windows'da bir dosya adlandırmanın başınızı belaya sokacağından bahsetmiyorum bile ...
Nathan Osman

2
Hafif bir yeniden düzenleme, yedek bir karakteri belirtmeyi kolaylaştırır. İlk olarak orijinal işlevsellik: '' .join (dosya adındaki c için c geçerli / chars else c '') veya her geçersiz karakter için değiştirilmiş bir karakter veya dize ile: '' .join (geçerli_chars içinde c ise c if geçerli '.') c in filename)
PeterVermont

102

Dize yöntemleriyle birlikte liste kavrayışını kullanabilirsiniz.

>>> s
'foo-bar#baz?qux@127/\\9]'
>>> "".join(x for x in s if x.isalnum())
'foobarbazqux1279'

3
Köşeli parantezleri atlayabileceğinizi unutmayın. Bu durumda birleştirmek için bir jeneratör ifadesi iletilir ve bu, başka bir şekilde kullanılmayan bir liste oluşturma adımını kaydeder.
Oben Sonne

31
+1 Bunu sevdim. Küçük bir değişiklik yaptım: "" .join ([x, x.isalnum () başka "_" x in için s]) - geçersiz öğelerin _ olduğu, boş bırakılmış gibi bir sonuç verir. Belki baţka birini atar.
Eddie Parker

12
Bu çözüm harika! Yine de küçük bir değişiklik yaptım:filename = "".join(i for i in s if i not in "\/:*?<>|")
Alex Krycek

1
Maalesef boşluklara ve noktalara bile izin vermiyor, ama fikri seviyorum.
tiktak

9
@tiktak: gidebileceğiniz boşluklara, noktalara ve alt çizgilere izin vermek için"".join( x for x in s if (x.isalnum() or x in "._- "))
hardmooth

95

Dizeleri dosya adı olarak kullanmanın nedeni nedir? İnsan okunabilirliği bir faktör değilse, dosya sistemi güvenli dizeleri üretebilen base64 modülü ile giderdim. Okunamayacak, ancak çarpışmalarla uğraşmanıza gerek kalmayacak ve tersine çevrilebilir.

import base64
file_name_string = base64.urlsafe_b64encode(your_string)

Güncelleme : Matthew yorumuna göre değişti.


1
Açıkçası, eğer durum buysa en iyi cevap budur.
user32141

60
Uyarı! base64 kodlaması, varsayılan olarak, birçok sistemdeki dosya adlarında geçerli olmayan geçerli çıktı olarak "/" karakterini içerir. Bunun yerine base64.urlsafe_b64encode (your_string) kullanın
Matthew

15
Aslında insan okunabilirliği, sadece hata ayıklama amacıyla olsa bile, neredeyse her zaman bir faktördür.
static_rtti

5
Python 3 your_stringbir bayt dizi veya bunun encode('ascii')çalışması için sonucu olması gerekir.
Noumenon

4
def url2filename(url): url = url.encode('UTF-8') return base64.urlsafe_b64encode(url).decode('UTF-8') def filename2url(f): return base64.urlsafe_b64decode(f).decode('UTF-8')
JeffProd

40

Sadece işleri daha da karmaşık hale getirmek için, sadece geçersiz karakterleri kaldırarak geçerli bir dosya adı almanız garanti edilmez. İzin verilen karakterler farklı dosya adlarında farklılık gösterdiğinden, muhafazakar bir yaklaşım, geçerli bir adı geçersiz bir ada dönüştürür. Aşağıdaki durumlarda özel işlem eklemek isteyebilirsiniz:

  • Dize tamamen geçersiz karakterler (size boş bir dize bırakarak)

  • Sonunda özel bir anlamı olan bir dize ile karşılaşırsınız, örneğin "." veya ".."

  • Pencerelerde belirli cihaz adları ayrılmıştır. Örneğin, "nul", "nul.txt" (veya aslında nul.anything) adında bir dosya oluşturamazsınız. Ayrılmış adlar:

    CON, PRN, AUX, NUL, COM1, COM2, COM3, COM4, ​​COM5, COM6, COM7, COM8, COM9, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8 ve LPT9

Büyük olasılıkla, bu durumlardan hiçbiriyle sonuçlanamayan dosya adlarına bir dizi dize ekleyerek ve geçersiz karakterleri çıkararak bu sorunları giderebilirsiniz.


25

Github'da python-slugify adında güzel bir proje var :

Yüklemek:

pip install python-slugify

Sonra kullan:

>>> from slugify import slugify
>>> txt = "This\ is/ a%#$ test ---"
>>> slugify(txt)
'this-is-a-test'

2
Bu kütüphaneyi seviyorum ama düşündüğüm kadar iyi değil. İlk test tamam ama aynı zamanda noktaları dönüştürür. Yani test.txtalır test-txtçok fazla olduğu.
therealmarv

23

S.Lott'un yanıtladığı gibi , bir dizeyi geçerli bir dosya adına nasıl dönüştürdükleri için Django Framework'e bakabilirsiniz .

En yeni ve güncellenmiş sürüm utils / text.py dosyasında bulunur ve aşağıdaki gibi "get_valid_filename" ifadesini tanımlar:

def get_valid_filename(s):
    s = str(s).strip().replace(' ', '_')
    return re.sub(r'(?u)[^-\w.]', '', s)

(Bkz. Https://github.com/django/django/blob/master/django/utils/text.py )


4
zaten django tembel için:django.utils.text import get_valid_filename
theannouncer

2
Normal ifadeye aşina değilseniz, re.sub(r'(?u)[^-\w.]', '', s)harf değil, sayı değil (0-9), alt çizgi ('_'), tire ('-') ve nokta ('.') Olmayan tüm karakterleri kaldırır. ). Buradaki "Harfler", 漢語 gibi tüm unicode harfleri içerir.
cowlinator

3
Uzunluğunu da kontrol etmek isteyebilirsiniz: Dosya adları 255 karakterle sınırlıdır (veya bilirsiniz, 32; FS'ye bağlı olarak)
Matthias Winkelmann

19

Sonuçta kullandığım çözüm bu:

import unicodedata

validFilenameChars = "-_.() %s%s" % (string.ascii_letters, string.digits)

def removeDisallowedFilenameChars(filename):
    cleanedFilename = unicodedata.normalize('NFKD', filename).encode('ASCII', 'ignore')
    return ''.join(c for c in cleanedFilename if c in validFilenameChars)

Unicodedata.normalize çağrısı, aksanlı karakterleri aksanlı eşdeğeriyle değiştirir; bu, yalnızca bunları çıkarmaktan daha iyidir. Bundan sonra izin verilmeyen tüm karakterler kaldırılır.

Çözümüm, izin verilmeyen dosya adlarından kaçınmak için bilinen bir dizenin başına gelmiyor, çünkü belirli dosya adı biçimim göz önüne alındığında bunların gerçekleşemeyeceğini biliyorum. Bunu yapmak için daha genel bir çözüm gerekir.


benzersiz ön
ekiniz

6
deve durumda .. ahh
demirli kirpi

Bu Python 3.6 ile çalışacak şekilde düzenlenebilir / güncellenebilir mi?
Wavesailor

13

Unix sistemlerinde dosya adlarında aslında herhangi bir kısıtlama olmadığını unutmayın.

  • \ 0 içeremez
  • İçeremez /

Diğer her şey adil bir oyundur.

$ touch "
> hatta çok satırlı
> haha
> ^ [[31m kırmızı ^ [[0m
> kötü "
$ ls -la 
-rw-r - r-- 0 Kas 17 23:39? hatta multiline? haha ​​?? [31m kırmızı? [0m? kötü
$ ls -lab
-rw-r - r-- 0 Kas 17 23:39 \ neven \ multiline \ nhaha \ n \ 033 [31m \ kırmızı \ \ 033 [0m \ nevil
$ perl -e 'için $ i (glob (q {./* hatta *})) {print $ i; } '
./
hatta çok satırlı
haha
 kırmızı 
kötülük

Evet, ANSI Renk Kodlarını bir dosya adında sakladım ve etkili olmalarını sağladım.

Eğlence için, bir dizin adına bir BEL karakteri koyun ve içine CD yazdığınızda ortaya çıkan eğlenceyi izleyin;)


OP, "Dosya
adının

1
@cowlinator cevabım gönderildikten 10 saat sonra açıklama eklendiğini ekledi :) OP'nin düzenleme günlüğünü kontrol edin.
Kent Fredric

12

Bir satırda:

valid_file_name = re.sub('[^\w_.)( -]', '', any_string)

daha okunabilir hale getirmek için '_' karakteri de ekleyebilirsiniz (örneğin, eğik çizgilerin değiştirilmesi durumunda)


7

"Filelike" olmayan bir şeyi değiştirmek için re.sub () yöntemini kullanabilirsiniz. Fakat aslında her karakter geçerli olabilir; bu yüzden bunu yapmak için önceden inşa edilmiş fonksiyonlar (inanıyorum) yoktur.

import re

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

/Tmp/filename.txt dosyasının dosya tanıtıcısıyla sonuçlanır.


5
Bir aralık olarak görünmemesi için grup eşleştiricide ilk önce tireye ihtiyacınız vardır. re.sub ('[^ - a-zA-Z0-9 _. ()] +', '', str)
phord

7
>>> import string
>>> safechars = bytearray(('_-.()' + string.digits + string.ascii_letters).encode())
>>> allchars = bytearray(range(0x100))
>>> deletechars = bytearray(set(allchars) - set(safechars))
>>> filename = u'#ab\xa0c.$%.txt'
>>> safe_filename = filename.encode('ascii', 'ignore').translate(None, deletechars).decode()
>>> safe_filename
'abc..txt'

Boş dizeleri, özel dosya adlarını ('nul', 'con', vb.) İşlemez.


Çeviri tabloları için +1, bu en etkili yöntemdir. Özel dosya adları / boşalmaları için basit bir ön koşul kontrolü yeterli olacaktır ve yabancı dönemler için de basit bir düzeltme.
Christian Witts

1
Çeviri bir regexp'den biraz daha verimli olsa da, aslında dosyayı açmaya çalışırsanız büyük olasılıkla cüce olacaktır, bu da şüphesiz yapmak istediğinizdir. Bu yüzden yukarıdaki karışıklıktan daha okunabilir bir regexp çözümünü tercih ediyorum
nosatalian

Ayrıca kara liste için de endişeliyim. Verilmiş, bu bir beyaz listeye dayanan bir kara liste, ama yine de. Daha az ... güvenli görünüyor. "Allchars" ın tam olduğunu nasıl anlarsınız?
isaaclw

@isaaclw: '.translate ()', 256 karakter dizesini çeviri tablosu olarak kabul eder (bayt-bayt çevirisi). '.maketrans ()' böyle bir dize oluşturur. Tüm değerler kapsanmaktadır; saf bir beyaz liste yaklaşımı
jfs

Dosya adı ne olacak? (tek bir nokta). Mevcut dizin bu adı kullandığı için Unixes üzerinde çalışmaz.
Finn Årup Nielsen

6

Yine de dikkatli olmalısın. Sadece latine diline bakıyorsanız, girişinizde açıkça söylenmez. Bazı kelimeler anlamsız olabilir veya yalnızca ascii karakterlerle temizlenirseniz başka bir anlam kazanabilirsiniz.

"forêt poésie" (orman şiiri) olduğunu düşünün, sanitasyonunuz "fort-posie" verebilir (güçlü + anlamsız bir şey)

Çince karakterler ile uğraşmak zorunda daha kötü.

"下 北 沢" sisteminiz bir süre sonra başarısızlığa mahkum olan ve çok yardımcı olmayan "---" ile sonuçlanabilir. Sadece dosyalarla uğraşırsanız, onları kontrol ettiğiniz jenerik bir zincir olarak adlandırmanızı veya karakterleri olduğu gibi tutmanızı öneririm. URI'ler için, neredeyse aynı.


6

Neden "osopen" i bir dene / hariç ile sarmıyor ve temel işletim sisteminin dosyanın geçerli olup olmadığını belirlemesine izin vermiyorsunuz?

Bu çok daha az iş gibi görünüyor ve hangi işletim sistemini kullanırsanız kullanın geçerlidir.


5
Yine de adı geçerli mi? Yani, işletim sistemi mutlu değilse, o zaman hala bir şeyler yapmanız gerekir, değil mi?
jeromej

1
Bazı durumlarda, OS / Dil sessizce dosya adınızı alternatif bir forma sokabilir, ancak bir dizin listesi yaptığınızda farklı bir ad alırsınız. Ve bu, "dosyayı buraya yazdığımda, ancak dosyayı aradığımda başka bir şey denir" sorununa yol açabilir. (VAX'ta duyduğum davranışlardan bahsediyorum ...)
Kent Fredric

Ayrıca, osopentek bir makinede çalışırken tespit edemediğiniz "dosya adının birden çok işletim sisteminde geçerli olması gerekir" .
LarsH

5

Diğer yorumların henüz ele almadığı başka bir sorun, açık bir şekilde geçerli bir dosya adı olmayan boş dizedir. Ayrıca, çok fazla karakter çektirmekten boş bir dize ile sonuçlanabilir.

Windows ayrılmış dosya adları ve noktalarla ilgili sorunlarda, “geçerli bir dosya adını rasgele kullanıcı girdisinden nasıl normalleştirebilirim?” Sorusunun en güvenli yanıtı nedir? "denemeyi bile denemeyin": bundan kaçınmak için başka bir yol bulabilirseniz (örneğin, veritabanındaki tamsayı birincil anahtarlarını dosya adı olarak kullanmak), bunu yapın.

Gerekirse ve gerçekten boşluklara ve '.' adın bir parçası olan dosya uzantıları için aşağıdakine benzer bir şey deneyin:

import re
badchars= re.compile(r'[^A-Za-z0-9_. ]+|^\.|\.$|^ | $|^$')
badnames= re.compile(r'(aux|com[1-9]|con|lpt[1-9]|prn)(\.|$)')

def makeName(s):
    name= badchars.sub('_', s)
    if badnames.match(name):
        name= '_'+name
    return name

Bu bile özellikle beklenmedik işletim sistemlerinde garanti edilemez - örneğin RISC işletim sistemi boşluklardan nefret eder ve 'kullanır.' dizin ayırıcı olarak.


4

Burada python-slugify yaklaşımını sevdim ama aynı zamanda istenmeyen noktalar da sıyırıyordu. Bu yüzden s3'e temiz bir dosya adı yüklemek için optimize ettim:

pip install python-slugify

Örnek kod:

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' # only unclean characters

Çıktı:

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

Bu çok güvenli, uzantısız dosya adlarıyla çalışır ve hatta yalnızca güvensiz karakterler dosya adları için çalışır (sonuç noneburada).


1
Bunu beğendim, tekerleği yeniden icat etmeyin, ihtiyacınız yoksa tüm Django çerçevesini içe aktarmayın, gelecekte korumak için doğrudan kod yapıştırmayın ve oluşturulan dize çalışır benzer harfleri güvenli harflerle eşleştirerek yeni dizeyi okumak daha kolaydır.
vicenteherrera

1
Tire yerine alt çizgi kullanmak için: name = slugify (s, separator = '_')
vicenteherrera

3

Yanıt python 3.6 için değiştirildi

import string
import unicodedata

validFilenameChars = "-_.() %s%s" % (string.ascii_letters, string.digits)
def removeDisallowedFilenameChars(filename):
    cleanedFilename = unicodedata.normalize('NFKD', filename).encode('ASCII', 'ignore')
    return ''.join(chr(c) for c in cleanedFilename if chr(c) in validFilenameChars)

Cevabınızı ayrıntılı olarak açıklayabilir misiniz?
Serenity

Aynı cevap Sophie Gage tarafından da kabul edildi. Ancak python 3.6
Jean-Robin Tremblay

2

Birçok cevap olduğunu anlıyorum, ancak çoğunlukla düzenli ifadelere veya harici modüllere güveniyorlar, bu yüzden kendi cevabımı atmak istiyorum. Saf bir python işlevi, harici modüle gerek yok, normal ifade kullanılmıyor. Benim yaklaşımım geçersiz karakterleri temizlemek değil, sadece geçerli karakterlere izin vermektir.

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    

İsterseniz, kendi geçerli karakterlerinizi validchars İngilizce alfabede bulunmayan ulusal harfleriniz gibi değişkene başlangıçta . Bu, isteyebileceğiniz veya istemeyebileceğiniz bir şeydir: UTF-8 üzerinde çalışmayan bazı dosya sistemleri ASCII olmayan karakterlerle ilgili sorunlar yaşayabilir.

Bu işlev, tek bir dosya adı geçerliliğini sınamak içindir, bu nedenle yol ayırıcılarını _ yerine geçersiz karakterleri dikkate alarak _ ile değiştirir. Bunu eklemek istiyorsanız if, os yol ayırıcısını içerecek şekilde değiştirmek önemsizdir .


1

Bu çözümlerin çoğu işe yaramıyor.

'/ merhaba / dünya' -> 'helloworld'

'/ helloworld' / -> 'helloworld'

Genel olarak istediğiniz şey bu değildir, her bağlantı için html'yi kaydettiğinizi, farklı bir web sayfası için html'nin üzerine yazacağınızı varsayalım.

Ben böyle bir dikte turşu:

{'helloworld': 
    (
    {'/hello/world': 'helloworld', '/helloworld/': 'helloworld1'},
    2)
    }

2, bir sonraki dosya adına eklenmesi gereken sayıyı temsil eder.

Her seferinde dikteden dosya adına bakıyorum. Orada değilse, gerekirse maksimum sayıyı ekleyerek yeni bir tane oluştururum.


Not, helloworld1 kullanıyorsanız, ayrıca helloworld1'in kullanımda olmadığını kontrol etmelisiniz ..
Robert

1

OP'nin tam olarak ne istediğini değil, benzersiz ve geri dönüşümlü dönüşümlere ihtiyacım olduğu için kullandığım şey bu:

# p3 code
def safePath (url):
    return ''.join(map(lambda ch: chr(ch) if ch in safePath.chars else '%%%02x' % ch, url.encode('utf-8')))
safePath.chars = set(map(lambda x: ord(x), '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+-_ .'))

Sonuç, en azından sistem yöneticisi açısından "bir şekilde" okunabilir.


Dosya adlarında boşluk olmadan bunun için bir sarıcı:def safe_filename(filename): return safePath(filename.strip().replace(' ','_'))
SpeedCoder5

1

Bir paket kurmanın sakıncası yoksa, bunun yararlı olması gerekir: https://pypi.org/project/pathvalidate/

Gönderen https://pypi.org/project/pathvalidate/#sanitize-a-filename :

from pathvalidate import sanitize_filename

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

Çıktı

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

0

Eminim bu harika bir cevap değildir, çünkü döngü yaptığı dizeyi değiştirir, ancak iyi çalışıyor gibi görünüyor:

import string
for chr in your_string:
 if chr == ' ':
   your_string = your_string.replace(' ', '_')
 elif chr not in string.ascii_letters or chr not in string.digits:
    your_string = your_string.replace(chr, '')

"".join( x for x in s if (x.isalnum() or x in "._- "))Bu yazı yorumlarda buldum
SergioAraujo

0

GÜNCELLEME

Bu 6 yaşındaki cevapta tüm bağlantılar tamir edilemedi.

Ayrıca, artık bu şekilde yapmazdım, sadece base64güvensiz karakterleri kodlayın veya bırakın. Python 3 örneği:

import re
t = re.compile("[a-zA-Z0-9.,_-]")
unsafe = "abc∂éåß®∆˚˙©¬ñ√ƒµ©∆∫ø"
safe = [ch for ch in unsafe if t.match(ch)]
# => 'abc'

İle base64 kodlama ve kod çözme yapabilirsiniz, böylece tekrar orijinal dosya adını alabilir.

Ancak, kullanım durumuna bağlı olarak rastgele bir dosya adı oluşturmak ve meta verileri ayrı bir dosya veya DB'de depolamak daha iyi olabilir.

from random import choice
from string import ascii_lowercase, ascii_uppercase, digits
allowed_chr = ascii_lowercase + ascii_uppercase + digits

safe = ''.join([choice(allowed_chr) for _ in range(16)])
# => 'CYQ4JDKE9JfcRzAZ'

ORİJİNAL LINKROTTEN YANIT :

bobcatProje sadece bunu yapar bir piton modülü içeriyor.

Tamamen sağlam değil, bu gönderiye ve bu yanıta bakın .

Bu nedenle, belirtildiği gibi: base64okunabilirliğin önemi yoksa kodlama muhtemelen daha iyi bir fikirdir.


Tüm bağlantılar öldü. Adamım, bir şey yap.
Barışçıl Kodlayıcı
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.