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.
os.path
sebenarnya memuat pustaka yang berbeda tergantung pada os (lihat catatan kedua dalam dokumentasi ). Jadi jika fungsi mengutip diterapkan dios.path
dalamnya 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.Jawaban:
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.Masih ada lagi, tetapi saya meninggalkannya, karena tidak membahas slugifikasi, tetapi melarikan diri.
sumber
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.slugify
Fungsi telah dipindahkan ke Django / util / text.py , dan file yang juga berisiget_valid_filename
fungsi.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.
sumber
valid_chars = frozenset(valid_chars)
tidak akan sakit. Ini 1,5 kali lebih cepat jika diterapkan ke allchars."CON"
pada Windows akan membuat Anda kesulitan ...Anda dapat menggunakan pemahaman daftar bersama-sama dengan metode string.
sumber
filename = "".join(i for i in s if i not in "\/:*?<>|")
"".join( x for x in s if (x.isalnum() or x in "._- "))
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.
Pembaruan : Diubah berdasarkan komentar Matius.
sumber
your_string
harus berupa array byte atau hasilencode('ascii')
agar ini berfungsi.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')
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.
sumber
Ada proyek bagus di Github yang disebut python-slugify :
Install:
Kemudian gunakan:
sumber
test.txt
mendapattest-txt
yang terlalu banyak.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:
(Lihat https://github.com/django/django/blob/master/django/utils/text.py )
sumber
django.utils.text import get_valid_filename
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 漢語.Ini adalah solusi yang akhirnya saya gunakan:
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.
sumber
Perlu diingat, sebenarnya tidak ada batasan nama file pada sistem Unix selain
Yang lainnya adalah permainan yang adil.
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;)
sumber
Dalam satu baris:
Anda juga dapat menempatkan karakter '_' untuk membuatnya lebih mudah dibaca (dalam kasus mengganti garis miring, misalnya)
sumber
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.
Akan menghasilkan filehandle ke /tmp/filename.txt.
sumber
Itu tidak menangani string kosong, nama file khusus ('nul', 'con', dll).
sumber
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.
sumber
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.
sumber
osopen
menjalankan di satu mesin.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:
Bahkan ini tidak dapat dijamin benar terutama pada OS yang tidak terduga - misalnya RISC OS membenci spasi dan menggunakan '.' sebagai pemisah direktori.
sumber
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:
Kode contoh:
Keluaran:
Ini sangat failafe, ia bekerja dengan nama file tanpa ekstensi dan bahkan berfungsi hanya untuk nama file karakter yang tidak aman (hasilnya ada di
none
sini).sumber
Jawaban dimodifikasi untuk python 3.6
sumber
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.
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
if
untuk memasukkan pemisah jalur os.sumber
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:
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.
sumber
Bukan apa yang diminta OP tetapi ini yang saya gunakan karena saya perlu konversi yang unik dan dapat dibalik:
Hasilnya "agak" dapat dibaca, setidaknya dari sudut pandang sysadmin.
sumber
def safe_filename(filename): return safePath(filename.strip().replace(' ','_'))
Jika Anda tidak keberatan menginstal paket, ini akan berguna: https://pypi.org/project/pathvalidate/
Dari https://pypi.org/project/pathvalidate/#sanitize-a-filename :
sumber
Saya yakin ini bukan jawaban yang bagus, karena ia memodifikasi string yang berulang, tetapi tampaknya berfungsi dengan baik:
sumber
"".join( x for x in s if (x.isalnum() or x in "._- "))
di komentar posting iniMEMPERBARUI
Semua tautan rusak tidak dapat diperbaiki dalam jawaban berusia 6 tahun ini.
Juga, saya juga tidak akan melakukannya dengan cara ini lagi, cukup
base64
menyandikan atau menjatuhkan karakter yang tidak aman. Contoh Python 3:Dengan
base64
Anda 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.
JAWABAN LINKROTTEN ASLI :
The
bobcat
proyek berisi modul python yang tidak hanya ini.Itu tidak sepenuhnya kuat, lihat posting ini dan balasan ini .
Jadi, seperti yang disebutkan:
base64
penyandian mungkin merupakan ide yang lebih baik jika keterbacaan tidak masalah.sumber