web-dev-qa-db-ja.com

(安全でない)文字列から(健全な/安全な)ファイル名を作成する

ランダムなUnicode文字列(michは何でもかまいません)から健全な/安全なファイル名(つまり、多少読みやすい、「奇妙な」文字などはありません)を作成したいです。

(関数がCocoa、ObjC、Pythonなどであるかどうかは関係ありません。)


もちろん、奇妙であるかもしれない無限の多くのキャラクターがあるかもしれません。したがって、ブラックリストを作成し、時間の経過とともにリストに追加することは実際には解決策ではありません。

ホワイトリストを作成できます。しかし、私はそれを定義する方法を本当に知りません。 [a-zA-Z0-9 .]は開始点ですが、通常の方法で表示できるUnicode文字も受け入れたいです。

42
Albert

Python:

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

これはUnicode文字を受け入れますが、改行などを削除します。

例:

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

与える:adblaç

編集するstr.isalnum()は、1ステップで英数字を実行します。 –以下のqueueoverflowからのコメント。ダノドノバンは、ドットを含めることをほのめかしました。

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

私の要件は控えめでした(生成されたファイル名は、いくつかの古代のモバイルOSを含む複数のオペレーティングシステムで有効である必要がありました)。私は結局:

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

その白には、英数字(a-z、A-Z、0-9)および下線がリストされています。一致する文字列が多数ある場合、正規表現をコンパイルしてキャッシュして効率を上げることができます。私の場合、大きな違いはありませんでした。

10
Ngure Nyaga

ここにはいくつかの合理的な答えがありますが、私の場合は、スペースと句読点を含む可能性のある文字列であるものを取得し、それらを単に削除するのではなく、アンダースコアに置き換えます。スペースはほとんどのOSで許容されるファイル名文字ですが、問題があります。また、私の場合、元の文字列にピリオドが含まれていた場合、ファイル名にパススルーしたくない、または「余分な拡張子」が生成されてしまう場合があります(拡張子を自分で追加しています)

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

6
uglycoyote

多かれ少なかれ、ここで正規表現で言及されていることですが、逆になります(リストされていないものを置き換えます):

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

ここには解決策はありません。考慮しなければならない問題のみです:

  • あなたの最小の最大ファイル名の長さは何ですか? (例:DOSは8〜11文字のみをサポートします;ほとんどのOSは256文字以上をサポートしません)

  • コンテキストで禁止されているファイル名は何ですか? (WindowsはCON.TXTとしてファイルを保存することをまだサポートしていません- https://blogs.msdn.Microsoft.com/oldnewthing/20031022-00/?p=4207 を参照してください)

  • ...には特定の意味(現在/親ディレクトリ)があるため、安全ではないことに注意してください。

  • 文字の削除または同じファイル名が複数回使用されているため、ファイル名が衝突するリスクがありますか?

データをハッシュし、その16進ダンプをファイル名として使用することを検討してください。

3
Dragon

Python:

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

(削除したい文字の例)文字列の前にあるrは、文字列がその生の形式で解釈されるようにし、バックスラッシュ\も削除できるようにします

編集:Pythonの正規表現ソリューション:

import re
re.sub(r'[]/\;,><&*:%=+@!#^()|?^', '', filename)
2
Remi