Подтвердить что ты не робот

Создать (нормальное/безопасное) имя файла из любой (небезопасной) строки

Я хочу создать нормальное/безопасное имя файла (т.е. несколько читаемый, никаких "странных" символов и т.д.) из некоторой случайной строки Unicode (mich может содержать только что-либо).

(Для меня не имеет значения, что функция Cocoa, ObjC, Python и т.д.)


Конечно, может быть бесконечное множество символов, которые могут быть странными. Таким образом, на самом деле это не решение иметь черный список и добавлять к нему все больше и больше.

У меня мог бы быть белый список. Однако я не знаю, как это определить. [a-zA-Z0-9 .] - это начало, но я также хочу принимать символы Unicode, которые могут отображаться обычным способом.

4b9b3361

Ответ 1

Python:

"".join([c for c in filename if c.isalpha() or c.isdigit() or c==' ']).rstrip()

это принимает символы Unicode, но удаляет разрывы строк и т.д.

Пример:

filename = u"ad\nbla'{-+\)(ç?"

дает: adblaç

изменить str.isalnum() делает буквенно-цифровой на один шаг. - комментарий от queueoverflow ниже. danodonovan намекнул на сохранение точки.

    keepcharacters = (' ','.','_')
    "".join(c for c in filename if c.isalnum() or c in keepcharacters).rstrip()

Ответ 2

Мои требования были консервативными (сгенерированные имена файлов должны были быть действительными для нескольких операционных систем, включая некоторые старые мобильные ОС). Я закончил с:

    "".join([c for c in text if re.match(r'\w', c)])

В белом списке перечислены буквенно-цифровые символы (a-z, A-Z, 0-9) и подчеркивание. Регулярное выражение может быть скомпилировано и кэшировано для эффективности, если есть много строк для сопоставления. Для моего случая это не имело бы существенной разницы.

Ответ 3

Здесь есть несколько разумных ответов, но в моем случае я хочу взять нечто, представляющее собой строку, которая может иметь пробелы и знаки препинания, и вместо того, чтобы просто удалить их, я бы предпочел заменить это подчеркиванием. Хотя пробелы являются допустимым символом имени файла в большинстве ОС, они проблематичны. Кроме того, в моем случае, если исходная строка содержала точку, которую я не хотел, чтобы это проходило через имя файла, или это генерировало бы "дополнительные расширения", которые я мог бы не хотеть (я сам добавляю расширение)

def make_safe_filename(s):
    def safe_char(c):
        if c.isalnum():
            return c
        else:
            return "_"
    return "".join(safe_char(c) for c in s).rstrip("_")

print(make_safe_filename( "hello you crazy $#^#& 2579 people!!! : die!!!" ) + ".gif")

принтами:

hello_you_crazy_______2579_people______die___.gif

Ответ 4

Более или менее то, что было упомянуто здесь с помощью регулярного выражения, но в обратном порядке (замените все НЕ перечисленные):

>>> import re
>>> filename = u"ad\nbla'{-+\)(ç1?"
>>> re.sub(r'[^\w\d-]','_',filename)
u'ad_bla__-_____1_'

Ответ 5

Здесь нет решений, только проблемы, которые вы должны учитывать:

  • Какова минимальная максимальная длина имени файла? (например, DOS поддерживает только 8-11 символов, большинство ОС не поддерживают > 256 символов)

  • какие имена файлов запрещены в каком-то контексте? (Windows все еще не поддерживает сохранение файла как CON.TXT - см. https://blogs.msdn.microsoft.com/oldnewthing/20031022-00/?p=42073)

  • помните, что . и .. имеют определенные значения (текущий/родительский каталог) и поэтому небезопасны.

  • существует ли риск, что имена файлов будут сталкиваться - либо из-за удаления символов, либо с тем же именем, которое используется несколько раз?

Рассмотрим только хэширование данных и использование hexdump этого имени файла?

Ответ 6

Python:

for c in r'[]/\;,><&*:%[email protected]!#^()|?^':
    filename = filename.replace(c,'')

(просто пример символов, которые вы хотите удалить) r перед строкой убеждается, что строка интерпретируется в необработанном формате, что позволяет также удалять обратную косую черту \

Изменить: regex решение в Python:

import re
re.sub(r'[]/\;,><&*:%[email protected]!#^()|?^', '', filename)

Ответ 7

Вот то, с чем я пришел, вдохновленный uglycoyote:

import time

def make_safe_filename(s):
    def safe_char(c):
        if c.isalnum() or c=='.':
            return c
        else:
            return "_"

    safe = ""
    last_safe=False
    for c in s:
      if len(safe) > 200:
        return safe + "_" + str(time.time_ns() // 1000000)

      safe_c = safe_char(c)
      curr_safe = c != safe_c
      if not last_safe or not curr_safe:
        safe += safe_c
      last_safe=curr_safe
    return safe

И для проверки:

print(make_safe_filename( "hello you crazy $#^#& 2579 people!!! : hi!!!hello you crazy $#^#& 2579 people!!! : hi!!!hello you crazy $#^#& 2579 people!!! : hi!!!hello you crazy $#^#& 2579 people!!! : hi!!!hello you crazy $#^#& 2579 people!!! : hi!!!hello you crazy $#^#& 2579 people!!! : hi!!!hello you crazy $#^#& 2579 people!!! : hi!!!hello you crazy $#^#& 2579 people!!! : hi!!!hello you crazy $#^#& 2579 people!!! : hi!!!hello you crazy $#^#& 2579 people!!! : hi!!!hello you crazy $#^#& 2579 people!!! : hi!!!hello you crazy $#^#& 2579 people!!! : hi!!!hello you crazy $#^#& 2579 people!!! : hi!!!hello you crazy $#^#& 2579 people!!! : hi!!!hello you crazy $#^#& 2579 people!!! : hi!!!hello you crazy $#^#& 2579 people!!! : hi!!!hello you crazy $#^#& 2579 people!!! : hi!!!hello you crazy $#^#& 2579 people!!! : hi!!!hello you crazy $#^#& 2579 people!!! : hi!!!hello you crazy $#^#& 2579 people!!! : hi!!!" ) + ".gif")