¿Convertir una cadena en un nombre de archivo válido?

Resuelto Sophie Gage asked hace 15 años • 28 respuestas

Tengo una cadena que quiero usar como nombre de archivo, por lo que quiero eliminar todos los caracteres que no estarían permitidos en los nombres de archivo, usando Python.

Prefiero ser estricto que lo contrario, así que digamos que quiero conservar solo letras, dígitos y un pequeño conjunto de otros caracteres como "_-.() ". ¿Cuál es la solución más elegante?

El nombre del archivo debe ser válido en múltiples sistemas operativos (Windows, Linux y Mac OS); es un archivo MP3 en mi biblioteca con el título de la canción como nombre de archivo, y se comparte y se realiza una copia de seguridad entre 3 máquinas.

Sophie Gage avatar Nov 17 '08 16:11 Sophie Gage
Aceptado

Puede consultar el marco de Django (¡pero tenga en cuenta su licencia!) para saber cómo crean un "slug" a partir de texto arbitrario. Un slug es compatible con URL y nombres de archivos.

Las utilidades de texto de Django definen una función, slugify()que probablemente sea el estándar de oro para este tipo de cosas. Básicamente, su código es el siguiente.

import unicodedata
import re

def slugify(value, allow_unicode=False):
    """
    Taken from https://github.com/django/django/blob/master/django/utils/text.py
    Convert to ASCII if 'allow_unicode' is False. Convert spaces or repeated
    dashes to single dashes. Remove characters that aren't alphanumerics,
    underscores, or hyphens. Convert to lowercase. Also strip leading and
    trailing whitespace, dashes, and underscores.
    """
    value = str(value)
    if allow_unicode:
        value = unicodedata.normalize('NFKC', value)
    else:
        value = unicodedata.normalize('NFKD', value).encode('ascii', 'ignore').decode('ascii')
    value = re.sub(r'[^\w\s-]', '', value.lower())
    return re.sub(r'[-\s]+', '-', value).strip('-_')

Y la versión anterior:

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

Hay más, pero lo omití, ya que no aborda la slugificación, sino el escape.

S.Lott avatar Nov 17 '2008 12:11 S.Lott

Puede utilizar la comprensión de listas junto con los métodos de cadena.

>>> s
'foo-bar#baz?qux@127/\\9]'
>>> "".join(x for x in s if x.isalnum())
'foobarbazqux1279'
 avatar Nov 17 '2008 09:11

¿Cuál es la razón para utilizar cadenas como nombres de archivos? Si la legibilidad humana no es un factor, elegiría el módulo base64 que puede producir cadenas seguras para el sistema de archivos. No será legible pero no tendrás que lidiar con colisiones y es reversible.

import base64
file_name_string = base64.urlsafe_b64encode(your_string)

Actualización : modificado según el comentario de Matthew.

Igal Serban avatar Nov 17 '2008 09:11 Igal Serban