У меня есть строка, которую я хочу использовать в качестве имени файла, поэтому я хочу удалить все символы, которые не допускаются в именах файлов, используя Python.
Я предпочел бы быть строгим, чем иначе, поэтому допустим, что я хочу сохранить только буквы, цифры и небольшой набор других символов, таких как "_-.() "
. Какое самое элегантное решение?
Имя файла должно быть действительным в нескольких операционных системах (Windows, Linux и Mac OS) - это файл MP3 в моей библиотеке с названием песни в качестве имени файла, который разделяется и резервируется между 3 компьютерами.
os.path
фактически загружает другую библиотеку в зависимости от операционной системы (см. Второе примечание в документации ). Поэтому, если в нем реализована функция цитирования,os.path
она может заключать в кавычки только строку для POSIX-безопасности при работе в системе POSIX или для Windows-безопасности при работе в Windows. Полученное имя файла не обязательно будет действительным для обоих окон и POSIX, о чем и спрашивает вопрос.Ответы:
Вы можете посмотреть на структуру Django, как они создают «слаг» из произвольного текста. Слаг - это URL-адрес и имя файла.
Текстовые утилиты Django определяют функцию,
slugify()
это, вероятно, золотой стандарт для такого рода вещей. По сути, их код следующий.Есть еще кое-что, но я не упомянул об этом, так как это не относится к слизи, а к спасению.
источник
value
. Если значение должно быть Unicode, то вы должны быть уверены, что это на самом деле Unicode. Или. Возможно, вы захотите пропустить нормализацию Юникода, если ваше фактическое значение на самом деле является строкой ASCII.slugify
Функция была перемещена в Джанго / Utils / text.py , и этот файл также содержитget_valid_filename
функцию.Этот подход белого списка (то есть, разрешающий только символы, присутствующие в valid_chars) будет работать, если нет ограничений на форматирование файлов или комбинацию допустимых символов (например, ".."), например, то, что вы говорите разрешил бы имя файла с именем ". txt", которое я считаю недопустимым в Windows. Так как это самый простой подход, я бы попытался удалить пробелы из valid_chars и добавить известную допустимую строку в случае ошибки, любой другой подход должен знать о том, что разрешено, где справиться с ограничениями именования файлов Windows и, таким образом, намного сложнее.
источник
valid_chars = frozenset(valid_chars)
не повредит. Это в 1,5 раза быстрее, если применяется к allchars."CON"
в Windows доставит вам неприятности ...Вы можете использовать понимание списка вместе со строковыми методами.
источник
filename = "".join(i for i in s if i not in "\/:*?<>|")
"".join( x for x in s if (x.isalnum() or x in "._- "))
В чем причина использования строк в качестве имен файлов? Если удобочитаемость не является фактором, я бы выбрал модуль base64, который может создавать безопасные строки файловой системы. Он не будет читаемым, но вам не придется иметь дело со столкновениями, и он обратим.
Обновление : изменено на основе комментария Мэтью.
источник
your_string
должен быть байтовый массив или результат,encode('ascii')
чтобы это работало.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')
Просто чтобы еще больше усложнить ситуацию, вы не гарантированно получите правильное имя файла, просто удалив недопустимые символы. Поскольку разрешенные символы различаются в разных именах файлов, консервативный подход может в итоге превратить действительное имя в недопустимое. Вы можете добавить специальную обработку для случаев, когда:
Строка содержит все недопустимые символы (оставляя вас с пустой строкой)
Вы получите строку со специальным значением, например, "." или ".."
На окнах определенные имена устройств зарезервированы. Например, вы не можете создать файл с именем "nul", "nul.txt" (или фактически nul.anything). Зарезервированные имена:
CON, PRN, AUX, NUL, COM1, COM2, COM3, COM4, COM5, COM6, COM7, COM7, COM8, COM9, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8 и LPT9
Вероятно, вы можете обойти эти проблемы, добавив некоторую строку в имена файлов, которые никогда не приведут к одному из этих случаев, и убрав недопустимые символы.
источник
На Github есть хороший проект, который называется python-slugify :
Установка:
Тогда используйте:
источник
test.txt
получаетсяtest-txt
слишком много.Так же, как ответил С.Лотт , вы можете посмотреть на Django Framework, как они преобразуют строку в правильное имя файла.
Самая последняя и обновленная версия находится в utils / text.py и определяет «get_valid_filename», который выглядит следующим образом:
(См. Https://github.com/django/django/blob/master/django/utils/text.py ).
источник
django.utils.text import get_valid_filename
re.sub(r'(?u)[^-\w.]', '', s)
удаляются все символы, которые не являются буквами, не цифрами (0-9), ни подчеркиванием ('_'), ни тире ('-'), ни точкой ('.'). ). «Буквы» здесь включают все буквы Unicode, такие как 漢語.Это решение, которое я в конечном итоге использовал:
Вызов unicodedata.normalize заменяет символы с акцентом на эквивалент без акцента, что лучше, чем просто удаление их. После этого все запрещенные символы удаляются.
Мое решение не добавляет предварительно известную строку, чтобы избежать возможных запрещенных имен файлов, потому что я знаю, что они не могут произойти, учитывая мой конкретный формат имени файла. Для этого потребуется более общее решение.
источник
Имейте в виду, на самом деле нет никаких ограничений на имена файлов в системах Unix, кроме
Все остальное - честная игра.
Да, я просто сохранил цветовые коды ANSI в имени файла, и они вступили в силу.
Для развлечения поместите персонажа BEL в имя каталога и посмотрите, как весело, когда вы вставляете в него CD;)
источник
В одной строке:
Вы также можете поставить символ '_', чтобы сделать его более читабельным (например, в случае замены косой черты)
источник
Вы можете использовать метод re.sub (), чтобы заменить что-либо, не похожее на файл. Но в действительности каждый персонаж может быть действительным; поэтому нет никаких готовых функций (я полагаю), чтобы сделать это.
Результатом будет дескриптор файла /tmp/filename.txt.
источник
Он не обрабатывает пустые строки, специальные имена файлов ('nul', 'con' и т. Д.).
источник
Хотя вы должны быть осторожны. Это не ясно сказано в вашем вступлении, если вы смотрите только на латинский язык. Некоторые слова могут стать бессмысленными или иметь другое значение, если вы очистите их только с помощью символов ascii.
представьте, что у вас есть «forêt poésie» (лесная поэзия), ваша дезинфекция может дать «fort-posie» (сильный + что-то бессмысленное)
Хуже, если вам приходится иметь дело с китайскими иероглифами.
«下 北 沢» ваша система может выполнить «---», что через некоторое время обречено на неудачу и не очень полезно. Поэтому, если вы имеете дело только с файлами, я бы посоветовал назвать их общей цепочкой, которой вы управляете, или оставить символы такими, какие они есть. Для URI примерно то же самое.
источник
Почему бы просто не обернуть «osopen» попыткой / исключением и позволить базовой ОС выяснить, является ли файл действительным?
Похоже, это гораздо меньше работы и действует независимо от того, какую ОС вы используете.
источник
osopen
работе на одном компьютере.Другая проблема, к которой еще не обращались другие комментарии, - это пустая строка, которая, очевидно, не является допустимым именем файла. Вы также можете получить пустую строку, чтобы убрать слишком много символов.
Что с зарезервированными в Windows именами файлов и проблемами с точками, самый безопасный ответ на вопрос «как нормализовать допустимое имя файла из произвольного пользовательского ввода?» это «даже не пытайтесь попробовать»: если вы можете найти любой другой способ избежать этого (например, используя целочисленные первичные ключи из базы данных в качестве имен файлов), сделайте это.
Если вы должны, и вам действительно нужно разрешить пробелы и '.' для расширений файлов как части имени, попробуйте что-то вроде:
Даже это не может быть гарантировано, особенно на неожиданных ОС - например, ОС RISC ненавидит пробелы и использует '.' в качестве разделителя каталогов.
источник
Мне здесь понравился подход, связанный с питоном, но он также удалял точки, что было нежелательно. Поэтому я оптимизировал его для загрузки чистого имени файла в s3 следующим образом:
Пример кода:
Вывод:
Это настолько отказоустойчиво, оно работает с именами файлов без расширения и даже работает только с именами файлов небезопасных символов (результат
none
здесь).источник
Ответ изменен для Python 3.6
источник
Я понимаю, что ответов много, но они в основном полагаются на регулярные выражения или внешние модули, поэтому я хотел бы добавить свой собственный ответ. Чистая функция Python, внешний модуль не требуется, регулярное выражение не используется. Мой подход состоит не в том, чтобы очистить недопустимые символы, а разрешить только допустимые.
если хотите, вы можете добавить свои собственные действительные символы в
validchars
переменную в начале, например, ваши национальные буквы, которых нет в английском алфавите. Это то, что вы можете или не хотите: некоторые файловые системы, которые не работают на UTF-8, могут по-прежнему иметь проблемы с не-ASCII-символами.Эта функция предназначена для проверки правильности одного имени файла, поэтому она заменит разделители пути на _, считая их недопустимыми символами. Если вы хотите добавить это, просто изменить
if
разделитель пути os.источник
Большинство из этих решений не работают.
'/ hello / world' -> 'helloworld'
'/ helloworld' / -> 'helloworld'
Обычно это не то, что вам нужно, скажем, вы сохраняете HTML для каждой ссылки, вы собираетесь переписать HTML для другой веб-страницы.
Я мариную такие слова, как:
2 представляет число, которое должно быть добавлено к следующему имени файла.
Я смотрю имя файла каждый раз из диктата. Если его там нет, я создаю новый, добавляя максимальное количество, если это необходимо.
источник
Не совсем то, о чем просил OP, но это то, что я использую, потому что мне нужны уникальные и обратимые преобразования:
Результат «несколько» читабелен, по крайней мере, с точки зрения системного администратора.
источник
def safe_filename(filename): return safePath(filename.strip().replace(' ','_'))
Если вы не возражаете против установки пакета, это может быть полезно: https://pypi.org/project/pathvalidate/
Из https://pypi.org/project/pathvalidate/#sanitize-a-filename :
источник
Я уверен, что это не очень хороший ответ, так как он изменяет зацикленную строку, но, похоже, работает нормально:
источник
"".join( x for x in s if (x.isalnum() or x in "._- "))
в этом посте комментариевОБНОВИТЬ
Все ссылки неработоспособны в этом 6-летнем ответе.
Кроме того, я бы больше так не делал, просто
base64
кодировал или сбрасывал небезопасные символы. Пример Python 3:С участием
base64
вы можете кодировать и декодировать, чтобы вы могли получить исходное имя файла снова.Но в зависимости от варианта использования вам может быть лучше сгенерировать случайное имя файла и сохранить метаданные в отдельном файле или БД.
ОРИГИНАЛЬНЫЙ LINKROTTEN ОТВЕТ :
bobcat
Проект содержит модуль питона , который делает именно это.Это не совсем надежно, см. Этот пост и этот ответ .
Итак, как отмечалось:
base64
кодирование, вероятно, является лучшей идеей, если читаемость не имеет значения.источник