Ubah string menjadi nama file yang valid?

298

Saya memiliki string yang ingin saya gunakan sebagai nama file, jadi saya ingin menghapus semua karakter yang tidak diizinkan dalam nama file, menggunakan Python.

Saya lebih suka bersikap tegas daripada yang lain, jadi katakanlah saya hanya ingin mempertahankan huruf, angka, dan satu set karakter kecil seperti "_-.() ". Apa solusi paling elegan?

Nama file harus valid pada beberapa sistem operasi (Windows, Linux dan Mac OS) - ini adalah file MP3 di perpustakaan saya dengan judul lagu sebagai nama file, dan dibagikan dan dicadangkan di antara 3 mesin.

Sophie Gage
sumber
17
Bukankah ini harus dibangun ke dalam modul os.path?
endolith
2
Mungkin, meskipun case use-nya membutuhkan satu jalur yang aman di semua platform, bukan hanya jalur saat ini, yang merupakan sesuatu yang tidak bisa ditangani opath.
javawizard
2
Untuk memperluas komentar di atas: desain saat ini os.pathsebenarnya memuat pustaka yang berbeda tergantung pada os (lihat catatan kedua dalam dokumentasi ). Jadi jika fungsi mengutip diterapkan di os.pathdalamnya hanya bisa mengutip string untuk keamanan POSIX ketika berjalan pada sistem POSIX atau untuk keamanan windows saat berjalan di windows. Nama file yang dihasilkan tidak harus valid di kedua jendela dan POSIX, yang merupakan pertanyaan yang diajukan.
dshepherd

Jawaban:

164

Anda dapat melihat kerangka kerja Django untuk bagaimana mereka membuat "siput" dari teks arbitrer. Siput adalah URL- dan ramah nama file.

Util teks Django mendefinisikan fungsi slugify(),, itu mungkin standar emas untuk hal semacam ini. Pada dasarnya, kode mereka adalah sebagai berikut.

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

Masih ada lagi, tetapi saya meninggalkannya, karena tidak membahas slugifikasi, tetapi melarikan diri.

S.Lott
sumber
11
Baris terakhir adalah: value = unicode (re.sub ('[- \ s + +', '-', value))
Joseph Turian
1
Terima kasih - saya bisa melewatkan sesuatu, tapi saya mendapatkan: "menormalkan () argumen 2 harus unicode, bukan str"
Alex Cook
"menormalkan () argumen 2". Berarti itu value. Jika nilainya harus Unicode, maka, Anda harus yakin itu sebenarnya Unicode. Atau. Anda mungkin ingin meninggalkan normalisasi unicode jika nilai aktual Anda sebenarnya adalah string ASCII.
S.Lott
8
Seandainya ada orang yang tidak melihat sisi positif dari pendekatan ini adalah bahwa ia tidak hanya menghilangkan karakter non-alpha, tetapi mencoba untuk menemukan pengganti yang baik terlebih dahulu (melalui normalisasi NFKD), jadi é menjadi e, superscript 1 menjadi normal 1, dll. Terima kasih
Michael Scott Cuthbert
48
The slugifyFungsi telah dipindahkan ke Django / util / text.py , dan file yang juga berisi get_valid_filenamefungsi.
Denilson Sá Maia
104

Pendekatan daftar putih ini (yaitu, hanya mengizinkan karakter yang ada di valid_chars) akan berfungsi jika tidak ada batasan pada pemformatan file atau kombinasi karakter yang valid yang ilegal (seperti ".."), misalnya, apa yang Anda katakan akan memungkinkan nama file bernama ". txt" yang menurut saya tidak valid pada Windows. Karena ini adalah pendekatan yang paling sederhana, saya akan mencoba untuk menghapus spasi dari valid_chars dan menambahkan string valid yang diketahui jika terjadi kesalahan, setiap pendekatan lain harus tahu tentang apa yang diizinkan di mana untuk mengatasi keterbatasan penamaan file Windows dan dengan demikian menjadi jauh lebih kompleks.

>>> 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'
Vinko Vrsalovic
sumber
7
valid_chars = frozenset(valid_chars)tidak akan sakit. Ini 1,5 kali lebih cepat jika diterapkan ke allchars.
jfs
2
Peringatan: Ini memetakan dua string berbeda ke string yang sama >>> import string >>> valid_chars = "- . ()% S% s"% (string.ascii_letters, string.digits) >>> valid_chars '- . () abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 '>>> filename = "a.com/hello/world" >>>' '.join (c untuk namafile jika c di valid_chars)' a.comhelloworld ".com/ a >helloworld ".com/>hosting di seluruh dunia </> nama dunia> http> ">>> '' .join (c untuk c dalam nama file jika c di valid_chars) 'a.comhelloworld' >>>
robert king
3
Belum lagi bahwa memberi nama file "CON"pada Windows akan membuat Anda kesulitan ...
Nathan Osman
2
Pengaturan ulang sedikit membuat menentukan karakter pengganti secara langsung. Pertama fungsionalitas aslinya: '' .join (c jika c di valid_chars else '' untuk c dalam nama file) atau dengan karakter atau string pengganti untuk setiap karakter yang tidak valid: '' .join (c jika c di valid_chars else '.' Untuk c in filename)
PeterVermont
101

Anda dapat menggunakan pemahaman daftar bersama-sama dengan metode string.

>>> s
'foo-bar#baz?qux@127/\\9]'
>>> "".join(x for x in s if x.isalnum())
'foobarbazqux1279'
John Mee
sumber
3
Perhatikan bahwa Anda dapat menghilangkan tanda kurung siku. Dalam hal ini ekspresi generator dilewatkan untuk bergabung, yang menyimpan langkah membuat daftar yang tidak digunakan.
Oben Sonne
31
+1 Suka ini. Sedikit modifikasi yang telah saya lakukan: "" .join ([x jika x.isalnum () lain "_" untuk x dalam s]) - akan menghasilkan hasil di mana item yang tidak valid adalah _, seperti mereka kosong. Mungkin thelps orang lain.
Eddie Parker
12
Solusi ini hebat! Saya membuat sedikit modifikasi:filename = "".join(i for i in s if i not in "\/:*?<>|")
Alex Krycek
1
Sayangnya itu bahkan tidak memungkinkan spasi dan titik, tapi saya suka idenya.
tiktak
9
@tiktak: untuk (juga) memungkinkan spasi, titik, dan garis bawah yang bisa Anda gunakan"".join( x for x in s if (x.isalnum() or x in "._- "))
hardmooth
95

Apa alasan untuk menggunakan string sebagai nama file? Jika keterbacaan manusia bukan faktor saya akan pergi dengan modul base64 yang dapat menghasilkan string sistem file yang aman. Ini tidak dapat dibaca tetapi Anda tidak harus berurusan dengan tabrakan dan itu dapat dibalik.

import base64
file_name_string = base64.urlsafe_b64encode(your_string)

Pembaruan : Diubah berdasarkan komentar Matius.

Igal Serban
sumber
1
Jelas ini adalah jawaban terbaik jika itu masalahnya.
user32141
60
Peringatan! pengkodean base64 secara default menyertakan karakter "/" sebagai output yang valid yang tidak valid dalam nama file pada banyak sistem. Alih-alih menggunakan base64.urlsafe_b64encode (your_string)
Matius
15
Sebenarnya keterbacaan manusia hampir selalu merupakan faktor, bahkan jika hanya untuk keperluan debugging.
static_rtti
5
Dalam Python 3 your_stringharus berupa array byte atau hasil encode('ascii')agar ini berfungsi.
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

Hanya untuk memperumit masalah, Anda tidak dijamin mendapatkan nama file yang valid hanya dengan menghapus karakter yang tidak valid. Karena karakter yang dibolehkan berbeda pada nama file yang berbeda, pendekatan konservatif akhirnya dapat mengubah nama yang valid menjadi yang tidak valid. Anda mungkin ingin menambahkan penanganan khusus untuk kasus-kasus di mana:

  • String adalah semua karakter yang tidak valid (meninggalkan Anda dengan string kosong)

  • Anda berakhir dengan string dengan makna khusus, misalnya "." atau ".."

  • Di windows, nama perangkat tertentu dicadangkan. Misalnya, Anda tidak dapat membuat file bernama "nul", "nul.txt" (atau nul.anything sebenarnya) Nama yang dipesan adalah:

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

Anda mungkin dapat mengatasi masalah ini dengan menambahkan beberapa string ke nama file yang tidak pernah dapat menghasilkan salah satu dari kasus ini, dan menghapus karakter yang tidak valid.

Brian
sumber
25

Ada proyek bagus di Github yang disebut python-slugify :

Install:

pip install python-slugify

Kemudian gunakan:

>>> from slugify import slugify
>>> txt = "This\ is/ a%#$ test ---"
>>> slugify(txt)
'this-is-a-test'
Shoham
sumber
2
Saya suka perpustakaan ini tetapi tidak sebagus yang saya kira. Pengujian awal ok tapi itu juga mengkonversi titik. Jadi test.txtmendapat test-txtyang terlalu banyak.
therealmarv
23

Sama seperti S.Lott menjawab, Anda dapat melihat Django Framework untuk bagaimana mereka mengonversi string ke nama file yang valid.

Versi terbaru dan terbaru ditemukan di utils / text.py, dan mendefinisikan "get_valid_filename", yaitu sebagai berikut:

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

(Lihat https://github.com/django/django/blob/master/django/utils/text.py )

cowlinator
sumber
4
untuk yang malas sudah di Django:django.utils.text import get_valid_filename
theannouncer
2
Jika Anda tidak terbiasa dengan regex, re.sub(r'(?u)[^-\w.]', '', s)hapus semua karakter yang bukan huruf, bukan angka (0-9), bukan garis bawah ('_'), bukan tanda hubung ('-'), dan bukan titik ('.' ). "Surat" di sini mencakup semua huruf unicode, seperti 漢語.
cowlinator
3
Anda mungkin ingin juga memeriksa panjangnya: Nama file dibatasi hingga 255 karakter (atau, Anda tahu, 32; tergantung pada FS)
Matthias Winkelmann
19

Ini adalah solusi yang akhirnya saya gunakan:

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)

Panggilan unicodedata.normalisasi menggantikan karakter beraksen dengan padanan yang tidak beraksen, yang lebih baik daripada hanya menghapusnya. Setelah itu semua karakter yang dilarang dihapus.

Solusi saya tidak menambahkan string yang dikenal untuk menghindari kemungkinan nama file yang tidak diizinkan, karena saya tahu mereka tidak dapat muncul mengingat format nama file saya yang khusus. Solusi yang lebih umum perlu dilakukan.

Sophie Gage
sumber
Anda harus dapat menggunakan uuid.uuid4 () untuk awalan unik Anda
SLF
6
kasing unta .. ahh
landak gila
Mungkinkah ini diedit / diperbarui untuk bekerja dengan Python 3.6?
Wavesailor
13

Perlu diingat, sebenarnya tidak ada batasan nama file pada sistem Unix selain

  • Mungkin tidak mengandung \ 0
  • Itu mungkin tidak mengandung /

Yang lainnya adalah permainan yang adil.

$ sentuh "
> bahkan multiline
> haha
> ^ [[31m merah ^ [[0m
> jahat "
$ ls -la 
-rw-r - r-- 0 Nov 17 23:39? bahkan multiline? haha ​​?? [31m merah? [0m? jahat
$ ls -lab
-rw-r - r-- 0 Nov 17 23:39 \ neven \ multiline \ nhaha \ n \ 033 [31m \ red \ \ 033 [0m \ nevil
$ perl -e 'untuk $ i saya (glob (q {./* even *})) {print $ i; } '
./
bahkan multiline
ha ha
 merah 
jahat

Ya, saya baru saja menyimpan Kode Warna ANSI dalam nama file dan menerapkannya.

Untuk hiburan, letakkan karakter BEL dalam nama direktori dan tonton kesenangan yang terjadi saat Anda memasukkan CD ke dalamnya;)

Kent Fredric
sumber
OP menyatakan bahwa "Nama file harus valid pada beberapa sistem operasi"
cowlinator
1
@ clinlinator bahwa klarifikasi ditambahkan 10 jam setelah jawaban saya diposting :) Periksa log edit OP.
Kent Fredric
12

Dalam satu baris:

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

Anda juga dapat menempatkan karakter '_' untuk membuatnya lebih mudah dibaca (dalam kasus mengganti garis miring, misalnya)

mnach
sumber
7

Anda bisa menggunakan metode re.sub () untuk mengganti apa pun yang bukan "filelike". Tetapi pada dasarnya, setiap karakter bisa valid; jadi tidak ada fungsi prebuilt (saya percaya), untuk menyelesaikannya.

import re

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

Akan menghasilkan filehandle ke /tmp/filename.txt.

gx.
sumber
5
Anda perlu tanda hubung untuk menjadi yang pertama dalam pencocokan grup sehingga tidak muncul sebagai rentang. 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'

Itu tidak menangani string kosong, nama file khusus ('nul', 'con', dll).

jfs
sumber
+1 untuk tabel terjemahan, sejauh ini merupakan metode yang paling efisien. Untuk nama file khusus / kosong, pemeriksaan pra-kondisi sederhana akan cukup dan untuk periode yang tidak tersedia itu adalah koreksi sederhana juga.
Christian Witts
1
Meskipun menerjemahkan sedikit lebih efisien daripada regexp, waktu itu kemungkinan besar akan dikerdilkan jika Anda benar-benar mencoba membuka file tersebut, yang tidak diragukan lagi ingin Anda lakukan. Jadi saya lebih suka lebih solusi regexp lebih mudah dibaca daripada kekacauan di atas
nosatalian
Saya juga khawatir tentang daftar hitam itu. Memang, ini adalah daftar hitam yang didasarkan pada daftar putih, tetapi tetap saja. Sepertinya kurang ... aman. Bagaimana Anda tahu bahwa "allchars" sebenarnya lengkap?
isaaclw
@isaaclw: '.translate ()' menerima string 256-char sebagai tabel terjemahan (terjemahan byte-ke-byte). '.maketrans ()' membuat string seperti itu. Semua nilai tercakup; itu adalah pendekatan daftar putih murni
jfs
Bagaimana dengan nama file '.' (satu titik). Itu tidak akan berfungsi pada Unix karena direktori saat ini menggunakan nama itu.
Finn Årup Nielsen
6

Padahal kamu harus hati-hati. Tidak jelas dikatakan dalam intro Anda, jika Anda hanya melihat bahasa latine. Beberapa kata dapat menjadi tidak berarti atau berarti lain jika Anda membersihkannya hanya dengan karakter ascii.

bayangkan Anda memiliki "forêt poésie" (puisi hutan), sanitasi Anda mungkin memberi "fort-posie" (kuat + sesuatu yang tidak berarti)

Lebih buruk jika Anda harus berurusan dengan karakter Cina.

"下 北 沢" sistem Anda mungkin berakhir melakukan "---" yang pasti akan gagal setelah beberapa saat dan tidak terlalu membantu. Jadi, jika Anda hanya berurusan dengan file, saya akan mendorong untuk menyebutnya sebagai rantai generik yang Anda kontrol atau untuk mempertahankan karakter apa adanya. Untuk URI, hampir sama.

Karlcow
sumber
6

Mengapa tidak hanya membungkus "osopen" dengan coba / kecuali dan biarkan OS yang mendasarinya memilah apakah file tersebut valid?

Ini sepertinya kurang berfungsi dan valid apa pun OS yang Anda gunakan.

James Anderson
sumber
5
Apakah itu valid nama? Maksud saya, jika OS tidak bahagia, maka Anda masih perlu melakukan sesuatu, bukan?
jeromej
1
Dalam beberapa kasus, OS / Bahasa dapat secara diam-diam mengubah nama file Anda menjadi bentuk alternatif, tetapi ketika Anda melakukan daftar direktori, Anda akan mendapatkan nama yang berbeda. Dan ini dapat menyebabkan masalah "ketika saya menulis file di sana, tetapi ketika saya mencari file itu disebut sesuatu yang lain" masalah. (Saya berbicara tentang perilaku yang pernah saya dengar di VAX ...)
Kent Fredric
Selain itu, "Nama file harus valid pada beberapa sistem operasi", yang tidak dapat Anda deteksi dengan osopen menjalankan di satu mesin.
LarsH
5

Masalah lain yang belum ditangani oleh komentar lain adalah string kosong, yang jelas bukan nama file yang valid. Anda juga dapat berakhir dengan string kosong dari pengupasan terlalu banyak karakter.

Apa dengan nama file Windows yang dicadangkan dan masalah dengan titik-titik, jawaban teraman untuk pertanyaan "bagaimana cara menormalkan nama file yang valid dari input pengguna yang sewenang-wenang?" adalah "jangan repot-repot mencoba": jika Anda dapat menemukan cara lain untuk menghindarinya (mis. menggunakan integer primary key dari database sebagai nama file), lakukan itu.

Jika Anda harus, dan Anda benar-benar perlu memberi ruang dan '.' untuk ekstensi file sebagai bagian dari nama, coba sesuatu seperti:

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

Bahkan ini tidak dapat dijamin benar terutama pada OS yang tidak terduga - misalnya RISC OS membenci spasi dan menggunakan '.' sebagai pemisah direktori.

bobince
sumber
4

Saya menyukai pendekatan python-slugify di sini, tetapi juga menghilangkan titik-titik yang tidak diinginkan. Jadi saya mengoptimalkannya untuk mengunggah nama file bersih ke s3 dengan cara ini:

pip install python-slugify

Kode contoh:

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

Keluaran:

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

Ini sangat failafe, ia bekerja dengan nama file tanpa ekstensi dan bahkan berfungsi hanya untuk nama file karakter yang tidak aman (hasilnya ada di nonesini).

karenanya
sumber
1
Saya suka ini, jangan menemukan kembali roda, jangan mengimpor kerangka Django keseluruhan jika Anda tidak membutuhkannya, jangan langsung menempelkan kode jika Anda tidak akan mempertahankannya di masa depan, dan membuat string mencoba untuk mencocokkan surat serupa dengan yang aman, sehingga string baru lebih mudah dibaca.
vicenteherrera
1
Untuk menggunakan garis bawah alih-alih tanda hubung: name = slugify (s, separator = '_')
vicenteherrera
3

Jawaban dimodifikasi untuk python 3.6

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)
Jean-Robin Tremblay
sumber
Bisakah Anda jelaskan jawaban Anda?
Ketenangan
Jawabannya sama dengan yang diterima oleh Sophie Gage. Tetapi telah dimodifikasi untuk bekerja pada python 3.6
Jean-Robin Tremblay
2

Saya menyadari ada banyak jawaban tetapi sebagian besar mengandalkan ekspresi reguler atau modul eksternal, jadi saya ingin memberikan jawaban saya sendiri. Fungsi python murni, tidak ada modul eksternal yang diperlukan, tidak ada ekspresi reguler yang digunakan. Pendekatan saya bukan untuk membersihkan karakter yang tidak valid, tetapi hanya mengizinkan yang valid.

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    

jika suka, Anda dapat menambahkan karakter valid Anda sendiri ke validchars variabel di awal, seperti huruf nasional Anda yang tidak ada dalam alfabet bahasa Inggris. Ini adalah sesuatu yang Anda mungkin atau mungkin tidak ingin: beberapa sistem file yang tidak berjalan pada UTF-8 mungkin masih memiliki masalah dengan karakter non-ASCII.

Fungsi ini untuk menguji validitas nama file tunggal, sehingga akan mengganti pemisah path dengan _ menganggap mereka karakter yang tidak valid. Jika Anda ingin menambahkan itu, itu sepele untuk memodifikasi ifuntuk memasukkan pemisah jalur os.

Tuncay Göncüoğlu
sumber
1

Sebagian besar solusi ini tidak berfungsi.

'/ halo / dunia' -> 'helloworld'

'/ helloworld' / -> 'helloworld'

Ini bukan yang Anda inginkan secara umum, katakanlah Anda menyimpan html untuk setiap tautan, Anda akan menimpa html untuk halaman web yang berbeda.

Saya acar dict seperti:

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

2 mewakili angka yang harus ditambahkan ke nama file berikutnya.

Saya mencari nama file setiap kali dari dikt. Jika tidak ada di sana, saya membuat yang baru, menambahkan nomor maks jika diperlukan.

raja robert
sumber
perhatikan, jika menggunakan helloworld1, Anda juga perlu memeriksa helloworld1 tidak digunakan dan sebagainya ..
robert king
1

Bukan apa yang diminta OP tetapi ini yang saya gunakan karena saya perlu konversi yang unik dan dapat dibalik:

# 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+-_ .'))

Hasilnya "agak" dapat dibaca, setidaknya dari sudut pandang sysadmin.

pembuat
sumber
Pembungkus untuk ini tanpa spasi dalam nama file:def safe_filename(filename): return safePath(filename.strip().replace(' ','_'))
SpeedCoder5
0

Saya yakin ini bukan jawaban yang bagus, karena ia memodifikasi string yang berulang, tetapi tampaknya berfungsi dengan baik:

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, '')
TankorSmash
sumber
Saya telah menemukan ini "".join( x for x in s if (x.isalnum() or x in "._- "))di komentar posting ini
SergioAraujo
0

MEMPERBARUI

Semua tautan rusak tidak dapat diperbaiki dalam jawaban berusia 6 tahun ini.

Juga, saya juga tidak akan melakukannya dengan cara ini lagi, cukup base64menyandikan atau menjatuhkan karakter yang tidak aman. Contoh Python 3:

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

Dengan base64Anda dapat menyandikan dan mendekode, sehingga Anda dapat mengambil nama file asli lagi.

Tetapi tergantung pada kasus penggunaan Anda mungkin lebih baik menghasilkan nama file acak dan menyimpan metadata dalam file atau DB yang terpisah.

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'

JAWABAN LINKROTTEN ASLI :

The bobcatproyek berisi modul python yang tidak hanya ini.

Itu tidak sepenuhnya kuat, lihat posting ini dan balasan ini .

Jadi, seperti yang disebutkan: base64penyandian mungkin merupakan ide yang lebih baik jika keterbacaan tidak masalah.

kabel
sumber
Semua tautan mati. Bung, lakukan sesuatu.
The Peaceful Coder