Transformer une chaîne en un nom de fichier valide?

298

J'ai une chaîne que je veux utiliser comme nom de fichier, donc je veux supprimer tous les caractères qui ne seraient pas autorisés dans les noms de fichiers, en utilisant Python.

Je préfère être strict qu'autrement, alors disons que je veux conserver uniquement des lettres, des chiffres et un petit ensemble d'autres caractères comme "_-.() ". Quelle est la solution la plus élégante?

Le nom de fichier doit être valide sur plusieurs systèmes d'exploitation (Windows, Linux et Mac OS) - c'est un fichier MP3 dans ma bibliothèque avec le titre du morceau comme nom de fichier, et est partagé et sauvegardé entre 3 machines.

Sophie Gage
la source
17
Cela ne devrait-il pas être intégré au module os.path?
endolith
2
Peut-être, bien que son cas d'utilisation nécessiterait un seul chemin d'accès sûr sur toutes les plates-formes, pas seulement celui actuel, ce que os.path n'est pas conçu pour gérer.
javawizard
2
Pour développer le commentaire ci-dessus: la conception actuelle de os.pathcharge en fait une bibliothèque différente selon le système d'exploitation (voir la deuxième note dans la documentation ). Donc, si une fonction de citation a été implémentée, os.pathelle ne peut citer que la chaîne pour POSIX-safety lors de l'exécution sur un système POSIX ou pour windows-safety lors de l'exécution sur Windows. Le nom de fichier résultant ne serait pas nécessairement valide à la fois sur Windows et POSIX, ce que demande la question.
dshepherd

Réponses:

164

Vous pouvez regarder le framework Django pour voir comment ils créent un "slug" à partir de texte arbitraire. Un slug est compatible URL et nom de fichier.

Les utilitaires de texte Django définissent une fonction, slugify()c'est probablement l'étalon-or pour ce genre de chose. Essentiellement, leur code est le suivant.

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

Il y a plus, mais je l'ai laissé de côté, car il ne traite pas de la slugification, mais de l'évasion.

S.Lott
la source
11
La dernière ligne doit être: value = unicode (re.sub ('[- \ s] +', '-', value))
Joseph Turian
1
Merci - il se peut que je manque quelque chose, mais je reçois: "l'argument normalize () 2 doit être unicode, pas str"
Alex Cook
"argument normaliser () 2". Signifie le value. Si la valeur doit être Unicode, alors, vous devez être sûr qu'il s'agit bien d'Unicode. Ou. Vous souhaiterez peut-être ignorer la normalisation Unicode si votre valeur réelle est en fait une chaîne ASCII.
S.Lott
8
Si quelqu'un n'a pas remarqué le côté positif de cette approche, elle ne supprime pas seulement les caractères non alpha, mais tente de trouver d'abord de bons substituts (via la normalisation NFKD), donc é devient e, un exposant 1 devient un normal 1, etc. Merci
Michael Scott Cuthbert
48
La slugifyfonction a été déplacée dans django / utils / text.py , et ce fichier contient également une get_valid_filenamefonction.
Denilson Sá Maia
104

Cette approche de liste blanche (c'est-à-dire, autoriser uniquement les caractères présents dans valid_chars) fonctionnera s'il n'y a pas de limites sur le formatage des fichiers ou une combinaison de caractères valides qui sont illégaux (comme ".."), par exemple, ce que vous dites permettrait un nom de fichier nommé ". txt" qui, je pense, n'est pas valide sous Windows. Comme c'est l'approche la plus simple, j'essaierais de supprimer les espaces blancs des valid_chars et d'ajouter une chaîne valide connue en cas d'erreur, toute autre approche devra savoir ce qui est autorisé où faire face aux limitations de nommage des fichiers Windows et donc être beaucoup plus complexe.

>>> 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
la source
7
valid_chars = frozenset(valid_chars)ne ferait pas de mal. Il est 1,5 fois plus rapide s'il est appliqué à allchars.
jfs
2
Avertissement: cela mappe deux chaînes différentes à la même chaîne >>> import chaîne >>> valid_chars = "- . ()% S% s"% (string.ascii_letters, string.digits) >>> valid_chars '- . () abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 '>>> filename = "a.com/hello/world" >>>' '.join (c pour c dans le nom de fichier si c in valid_chars)' a.comhelloworld '>>> filename = "a.com/helloworld ">>> '' .join (c pour c dans le nom de fichier si c dans valid_chars) 'a.comhelloworld' >>>
robert king
3
Sans oublier que nommer un fichier "CON"sous Windows vous causera des ennuis ...
Nathan Osman
2
Un léger réarrangement facilite la spécification d'un caractère de substitution. D'abord la fonctionnalité d'origine: '' .join (c si c dans valid_chars else '' pour c dans filename) ou avec un caractère ou une chaîne substituée pour chaque caractère invalide: '' .join (c si c dans valid_chars else '.' For c dans le nom de fichier)
PeterVermont
101

Vous pouvez utiliser la compréhension de liste avec les méthodes de chaîne.

>>> s
'foo-bar#baz?qux@127/\\9]'
>>> "".join(x for x in s if x.isalnum())
'foobarbazqux1279'
John Mee
la source
3
Notez que vous pouvez omettre les crochets. Dans ce cas, une expression de générateur est transmise à join, ce qui évite de créer une liste autrement inutilisée.
Oben Sonne
31
+1 J'ai adoré ça. Légère modification que j'ai effectuée: "" .join ([x if x.isalnum () else "_" for x in s]) - donnerait un résultat où les éléments invalides sont _, comme s'ils étaient vides. Peut-être que quelqu'un aide quelqu'un d'autre.
Eddie Parker
12
Cette solution est géniale! J'ai cependant apporté une légère modification:filename = "".join(i for i in s if i not in "\/:*?<>|")
Alex Krycek
1
Malheureusement, il ne permet même pas d'espaces et de points, mais j'aime l'idée.
tiktak
9
@tiktak: pour (également) autoriser les espaces, les points et les "".join( x for x in s if (x.isalnum() or x in "._- "))
traits de
95

Quelle est la raison d'utiliser les chaînes comme noms de fichiers? Si la lisibilité humaine n'est pas un facteur, j'irais avec le module base64 qui peut produire des chaînes sûres du système de fichiers. Il ne sera pas lisible mais vous n'aurez pas à gérer les collisions et il est réversible.

import base64
file_name_string = base64.urlsafe_b64encode(your_string)

Mise à jour : modifié en fonction du commentaire de Matthew.

Igal Serban
la source
1
C'est évidemment la meilleure réponse si tel est le cas.
user32141
60
Avertissement! Le codage base64 par défaut inclut le caractère "/" comme sortie valide qui n'est pas valide dans les noms de fichiers sur de nombreux systèmes. Utilisez plutôt base64.urlsafe_b64encode (your_string)
Matthieu
15
En fait, la lisibilité humaine est presque toujours un facteur, ne serait-ce qu'à des fins de débogage.
static_rtti
5
En Python 3 your_stringdoit être un tableau d'octets ou le résultat de encode('ascii')pour que cela fonctionne.
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

Juste pour compliquer encore les choses, vous n'êtes pas assuré d'obtenir un nom de fichier valide simplement en supprimant les caractères non valides. Étant donné que les caractères autorisés diffèrent selon les noms de fichiers différents, une approche conservatrice pourrait finir par transformer un nom valide en nom invalide. Vous voudrez peut-être ajouter un traitement spécial pour les cas où:

  • La chaîne est composée de tous les caractères invalides (vous laissant avec une chaîne vide)

  • Vous vous retrouvez avec une chaîne avec une signification spéciale, par exemple "." ou ".."

  • Sous Windows, certains noms d'appareils sont réservés. Par exemple, vous ne pouvez pas créer un fichier nommé "nul", "nul.txt" (ou nul.anything en fait) Les noms réservés sont:

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

Vous pouvez probablement contourner ces problèmes en ajoutant une chaîne aux noms de fichiers qui ne peuvent jamais entraîner l'un de ces cas et en supprimant les caractères non valides.

Brian
la source
25

Il y a un joli projet sur Github appelé python-slugify :

Installer:

pip install python-slugify

Utilisez ensuite:

>>> from slugify import slugify
>>> txt = "This\ is/ a%#$ test ---"
>>> slugify(txt)
'this-is-a-test'
Shoham
la source
2
J'aime cette bibliothèque mais ce n'est pas aussi bon que je le pensais. Test initial correct mais il convertit également les points. Donc , test.txtobtient ce test-txtqui est trop.
therealmarv
23

Tout comme S.Lott a répondu, vous pouvez regarder le Framework Django pour voir comment ils convertissent une chaîne en un nom de fichier valide.

La version la plus récente et mise à jour se trouve dans utils / text.py et définit "get_valid_filename", qui est la suivante:

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

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

cowlinator
la source
4
pour les paresseux déjà sur django:django.utils.text import get_valid_filename
theeannouncer
2
Dans le cas où vous n'êtes pas familier avec l'expression régulière, re.sub(r'(?u)[^-\w.]', '', s)supprime tous les caractères qui ne sont pas des lettres, pas des chiffres (0-9), pas le trait de soulignement ('_'), pas le tiret ('-') et pas le point ('.' ). "Lettres" comprend ici toutes les lettres Unicode, telles que 漢語.
cowlinator
3
Vous pouvez également vérifier la longueur: les noms de fichiers sont limités à 255 caractères (ou, vous le savez, 32; selon la FS)
Matthias Winkelmann
19

Voici la solution que j'ai finalement utilisée:

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)

L'appel unicodedata.normalize remplace les caractères accentués par l'équivalent non accentué, ce qui est mieux que simplement les supprimer. Après cela, tous les caractères interdits sont supprimés.

Ma solution ne ajoute pas de chaîne connue pour éviter d'éventuels noms de fichiers non autorisés, car je sais qu'ils ne peuvent pas se produire compte tenu de mon format de nom de fichier particulier. Une solution plus générale devrait le faire.

Sophie Gage
la source
vous devriez pouvoir utiliser uuid.uuid4 () pour votre préfixe unique
slf
6
étui à chameau .. ahh
hérisson dément
Pourrait-il être édité / mis à jour pour fonctionner avec Python 3.6?
Wavesailor
13

Gardez à l'esprit qu'il n'y a en fait aucune restriction sur les noms de fichiers sur les systèmes Unix autres que

  • Il ne peut pas contenir \ 0
  • Il ne doit pas contenir /

Tout le reste est un jeu équitable.

$ touch "
> même multiligne
> haha
> ^ [[31m rouge ^ [[0m
> mal "
$ ls -la 
-rw-r - r-- 0 nov 17 23:39? même multiligne? haha ​​?? [31m rouge? [0m? evil
$ ls -lab
-rw-r - r-- 0 nov 17 23:39 \ neven \ multiline \ nhaha \ n \ 033 [31m \ red \ \ 033 [0m \ nevil
$ perl -e 'pour mon $ i (glob (q {./* even *})) {print $ i; } '
./
même multiligne
haha
 rouge 
mal

Oui, je viens de stocker les codes de couleur ANSI dans un nom de fichier et de les faire prendre effet.

Pour le divertissement, mettez un caractère BEL dans un nom de répertoire et regardez le plaisir qui s'ensuit lorsque vous y insérez un CD;)

Kent Fredric
la source
L'OP indique que "le nom de fichier doit être valide sur plusieurs systèmes d'exploitation"
cowlinator
1
@cowlinator que la clarification a été ajoutée 10 heures après la publication de ma réponse :) Consultez le journal d'édition du PO.
Kent Fredric
12

En une seule ligne:

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

vous pouvez également mettre le caractère '_' pour le rendre plus lisible (en cas de remplacement de barres obliques, par exemple)

mnach
la source
7

Vous pouvez utiliser la méthode re.sub () pour remplacer tout ce qui n'est pas "filelike". Mais en effet, chaque caractère pourrait être valide; il n'y a donc pas de fonctions prédéfinies (je crois), pour le faire.

import re

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

Cela entraînerait un descripteur de fichier dans /tmp/filename.txt.

gx.
la source
5
Vous avez besoin du tiret pour aller en premier dans la correspondance de groupe afin qu'il n'apparaisse pas comme une plage. 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'

Il ne gère pas les chaînes vides, les noms de fichiers spéciaux («nul», «con», etc.).

jfs
la source
+1 pour les tables de traduction, c'est de loin la méthode la plus efficace. Pour les noms de fichiers / vidages spéciaux, une simple vérification des conditions préalables suffit et pour les périodes étrangères, c'est aussi une simple correction.
Christian Witts
1
Bien que la traduction soit légèrement plus efficace qu'une expression rationnelle, ce temps sera probablement éclipsé si vous essayez réellement d'ouvrir le fichier, ce que vous avez sans aucun doute l'intention de faire. Ainsi, je préfère plus une solution d'expression rationnelle plus lisible que le désordre ci
nosatalian
Je suis également préoccupé par la liste noire. Certes, c'est une liste noire qui est basée sur une liste blanche, mais quand même. Cela semble moins ... sûr. Comment savez-vous que "allchars" est réellement terminé?
isaaclw
@isaaclw: '.translate ()' accepte une chaîne de 256 caractères comme table de traduction (traduction octet à octet). '.maketrans ()' crée une telle chaîne. Toutes les valeurs sont couvertes; c'est une approche pure liste blanche
jfs
Et le nom de fichier '.' (un seul point). Cela ne fonctionnerait pas sur Unix car le répertoire actuel utilise ce nom.
Finn Årup Nielsen
6

Mais il faut être prudent. Ce n'est pas clairement dit dans votre intro, si vous ne regardez que la langue latine. Certains mots peuvent perdre leur sens ou un autre sens si vous les désinfectez uniquement avec des caractères ascii.

imaginez que vous avez "forêt poésie" (poésie forestière), votre assainissement pourrait donner "fort-posie" (fort + quelque chose de dénué de sens)

Pire encore si vous devez gérer des caractères chinois.

"下 北 沢" votre système pourrait finir par faire "---" qui est voué à l'échec après un certain temps et n'est pas très utile. Donc, si vous ne traitez qu'avec des fichiers, j'encourage à les appeler une chaîne générique que vous contrôlez ou à conserver les caractères tels quels. Pour les URI, à peu près la même chose.

karlcow
la source
6

Pourquoi ne pas simplement envelopper le "osopen" avec un try / except et laisser le système d'exploitation sous-jacent trier si le fichier est valide?

Cela semble beaucoup moins de travail et est valable quel que soit le système d'exploitation que vous utilisez.

James Anderson
la source
5
Est-ce que cela valide le nom? Je veux dire, si le système d'exploitation n'est pas content, alors vous devez toujours faire quelque chose, non?
jeromej
1
Dans certains cas, le système d'exploitation / la langue peut silencieusement fusionner votre nom de fichier sous une autre forme, mais lorsque vous effectuez une liste de répertoires, vous obtiendrez un nom différent. Et cela peut conduire à un problème "lorsque j'écris le fichier là-bas, mais lorsque je cherche le fichier, il s'appelle autre chose". (Je parle de comportements dont j'ai entendu parler sur VAX ...)
Kent Fredric
De plus, "Le nom de fichier doit être valide sur plusieurs systèmes d'exploitation", ce que vous ne pouvez pas détecter avec un osopenfonctionnement sur une seule machine.
LarsH
5

Un autre problème que les autres commentaires n'ont pas encore résolu est la chaîne vide, qui n'est évidemment pas un nom de fichier valide. Vous pouvez également vous retrouver avec une chaîne vide en supprimant trop de caractères.

Qu'en est-il des noms de fichiers réservés de Windows et des problèmes avec les points, la réponse la plus sûre à la question "comment normaliser un nom de fichier valide à partir d'une entrée utilisateur arbitraire?" est "ne vous embêtez même pas": si vous pouvez trouver un autre moyen de l'éviter (par exemple en utilisant des clés primaires entières d'une base de données comme noms de fichiers), faites-le.

Si vous devez, et vous devez vraiment autoriser les espaces et '.' pour les extensions de fichier dans le nom, essayez quelque chose comme:

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

Même cela ne peut pas être garanti correctement, en particulier sur les systèmes d'exploitation inattendus - par exemple, RISC OS déteste les espaces et utilise ''. comme séparateur de répertoire.

bobince
la source
4

J'ai aimé l'approche python-slugify ici, mais elle supprimait également les points, ce qui n'était pas souhaité. Je l'ai donc optimisé pour télécharger un nom de fichier propre vers s3 de cette façon:

pip install python-slugify

Exemple de code:

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

Production:

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

C'est tellement sûr, cela fonctionne avec des noms de fichiers sans extension et cela ne fonctionne même que pour les noms de fichiers de caractères dangereux (le résultat est noneici).

therealmarv
la source
1
J'aime ça, ne réinventez pas la roue, n'importez pas l'intégralité du framework Django si vous n'en avez pas besoin, ne collez pas directement le code si vous ne le maintenez pas à l'avenir, et la chaîne générée essaie pour faire correspondre des lettres similaires à des lettres sûres, donc la nouvelle chaîne est plus facile à lire.
vicenteherrera
1
Pour utiliser le soulignement au lieu du tiret: nom = slugify (s, separator = '_')
vicenteherrera
3

Réponse modifiée pour 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
la source
Pourriez-vous expliquer votre réponse en détail?
Serenity
C'est la même réponse acceptée par Sophie Gage. Mais il a été modifié pour fonctionner sur python 3.6
Jean-Robin Tremblay
2

Je me rends compte qu'il existe de nombreuses réponses, mais elles reposent principalement sur des expressions régulières ou des modules externes, donc je voudrais ajouter ma propre réponse. Une fonction python pure, aucun module externe nécessaire, aucune expression régulière utilisée. Mon approche n'est pas de nettoyer les caractères invalides, mais de n'autoriser que ceux valides.

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    

si vous le souhaitez, vous pouvez ajouter vos propres caractères valides à la validcharsvariable au début, comme vos lettres nationales qui n'existent pas dans l'alphabet anglais. C'est quelque chose que vous pouvez ou ne voulez pas: certains systèmes de fichiers qui ne fonctionnent pas sur UTF-8 peuvent toujours avoir des problèmes avec les caractères non ASCII.

Cette fonction consiste à tester la validité d'un nom de fichier unique, elle remplacera donc les séparateurs de chemin par _ les considérant comme des caractères non valides. Si vous souhaitez ajouter cela, il est trivial de modifier le ifpour inclure le séparateur de chemin os.

Tuncay Göncüoğlu
la source
1

La plupart de ces solutions ne fonctionnent pas.

'/ bonjour / monde' -> 'helloworld'

'/ helloworld' / -> 'helloworld'

Ce n'est pas ce que vous voulez en général, disons que vous enregistrez le code HTML pour chaque lien, vous allez remplacer le code HTML pour une page Web différente.

Je décapage un dicton tel que:

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

2 représente le numéro qui doit être ajouté au nom de fichier suivant.

Je recherche le nom de fichier à chaque fois dans le dict. S'il n'est pas là, j'en crée un nouveau, en ajoutant le nombre maximum si nécessaire.

Robert King
la source
Remarque, si vous utilisez helloworld1, vous devez également vérifier que helloworld1 n'est pas utilisé, etc.
robert king
1

Pas exactement ce qu'OP demandait mais c'est ce que j'utilise car j'ai besoin de conversions uniques et réversibles:

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

Le résultat est "quelque peu" lisible, du moins d'un point de vue administrateur système.

makeroo
la source
Un wrapper pour cela sans espaces dans les noms de fichiers:def safe_filename(filename): return safePath(filename.strip().replace(' ','_'))
SpeedCoder5
1

Si cela ne vous dérange pas d'installer un package, cela devrait être utile: https://pypi.org/project/pathvalidate/

Depuis 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")

Production

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
Stavros
la source
0

Je suis sûr que ce n'est pas une bonne réponse, car cela modifie la chaîne sur laquelle il boucle, mais cela semble bien fonctionner:

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
la source
J'ai trouvé cela "".join( x for x in s if (x.isalnum() or x in "._- "))sur ce post commentaires
SergioAraujo
0

METTRE À JOUR

Tous les liens sont irréparables dans cette réponse de 6 ans.

De plus, je ne le ferais plus de cette façon, juste base64encoder ou supprimer des caractères dangereux. Exemple Python 3:

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

Avec base64vous pouvez encoder et décoder, vous pouvez donc récupérer à nouveau le nom de fichier d'origine.

Mais selon le cas d'utilisation, il serait préférable de générer un nom de fichier aléatoire et de stocker les métadonnées dans un fichier ou une base de données séparé.

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'

RÉPONSE ORIGINALE LINKROTTEN :

Le bobcatprojet contient un module python qui fait exactement cela.

Ce n'est pas complètement robuste, voir ce post et cette réponse .

Donc, comme indiqué: l' base64encodage est probablement une meilleure idée si la lisibilité n'a pas d'importance.

fils
la source
Tous les liens sont morts. Mec, fais quelque chose.
The Peaceful Coder