문자열을 올바른 파일 이름으로 변환하시겠습니까?
파일명으로 사용하고 싶은 문자열이 있기 때문에 파일명에 사용할 수 없는 문자를 Python을 사용하여 모두 삭제하고 싶습니다.
엄격히 이 더 좋기 나 숫자, 그 의 작은 , 예를 '먹다', '먹다', '먹다', '먹다', '먹다', '먹다', '먹다', '먹다', '먹다', '먹다', '먹다', '먹다', '먹다' 같은 "_-.() "
장장 우아 ?해 결? ?? ???
파일명은 복수의 operating system(Windows, Linux, Mac OS)에서 유효할 필요가 있습니다.이 파일은 라이브러리 내의 MP3 파일로, 곡의 제목을 파일명으로 하고, 3대의 머신간에 공유 및 백업됩니다.
임의의 텍스트에서 "slug"을 작성하는 방법을 Django 프레임워크에서 확인할 수 있습니다.slug는 URL과 파일명으로 구분됩니다.
Django text utils는 함수를 정의합니다.이것은 아마도 이러한 종류의 금본위제일 것입니다.기본적으로 그들의 코드는 다음과 같다.
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('-_')
이전 버전은 다음과 같습니다.
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
더 있어요, 하지만 빼먹었어요. 왜냐하면 그건 민달팽이를 다루는 게 아니라 탈출하는 거니까요.
리스트 이해는 문자열 방식과 함께 사용할 수 있습니다.
>>> s
'foo-bar#baz?qux@127/\\9]'
>>> "".join(x for x in s if x.isalnum())
'foobarbazqux1279'
이 화이트리스트 접근법(즉, valid_chars에 있는 문자만 허용)은 파일 형식 또는 유효한 문자 조합에 제한이 없는 경우(예를 들어 ".." 등), Windows에서는 유효하지 않다고 생각되는 파일 이름 ".txt"를 허용합니다.이것이 valid_chars에서 공백을 제거하고 오류 발생 시 이미 알려진 유효한 문자열 앞에 추가하는 가장 간단한 접근법이기 때문에 다른 접근법은 Windows 파일 이름 지정 제한에 대처하는 데 무엇이 허용되는지 알아야 하며, 따라서 훨씬 더 복잡합니다.
>>> 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'
문자열을 파일 이름으로 사용하는 이유는 무엇입니까?사람의 가독성이 문제가 되지 않는다면 파일 시스템의 안전한 문자열을 생성할 수 있는 base64 모듈로 하겠습니다.읽을 수는 없지만 충돌에 대처할 필요는 없으며 되돌릴 수도 있습니다.
import base64
file_name_string = base64.urlsafe_b64encode(your_string)
업데이트: Matthew 코멘트에 따라 변경되었습니다.
더 복잡한 것은 잘못된 문자를 제거한다고 해서 올바른 파일 이름을 얻을 수 있다는 보장은 없다는 것입니다.허용되는 문자는 파일명에 따라 다르기 때문에 보수적인 접근으로 인해 유효한 이름이 유효하지 않은 이름으로 바뀔 수 있습니다.다음과 같은 경우에 특별한 취급을 추가할 수 있습니다.
문자열이 모두 유효하지 않은 문자입니다(빈 문자열만 남음).
결국 특별한 의미를 가진 문자열(예: "" 또는 ".."
Windows 에서는, 특정의 디바이스명이 예약되어 있습니다.예를 들어 "nul", "nul.txt"(또는 nul.txt)라는 이름의 파일을 생성할 수 없습니다.예약된 이름은 다음과 같습니다.
CON, PRN, AUX, NUL, COM1, COM2, COM3, COM4, COM5, COM6, COM8, COM9, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT3, LPT7, LPT, LPT4, LPT3, LPT1, LPT3, LPT1, LPT3, LPT1, LPT3, LPT1, LPT3, LPT3
이러한 문제를 회피하려면 파일 이름에 몇 개의 문자열을 추가하여 이러한 경우 중 하나가 발생하지 않도록 하고 비활성 문자를 삭제해야 합니다.
Github에는 python-slugify라는 멋진 프로젝트가 있습니다.
인스톨:
pip install python-slugify
다음으로 다음을 사용합니다.
>>> from slugify import slugify
>>> txt = "This\ is/ a%#$ test ---"
>>> slugify(txt)
'this-is-a-test'
S처럼.Lott가 대답했습니다.Django Framework에서 문자열을 유효한 파일명으로 변환하는 방법을 확인할 수 있습니다.
최신 업데이트버전은 utils/text.py에서 찾을 수 있으며 다음과 같은 "get_valid_module"을 정의합니다.
def get_valid_filename(s):
s = str(s).strip().replace(' ', '_')
return re.sub(r'(?u)[^-\w.]', '', s)
( https://github.com/django/django/blob/master/django/utils/text.py 를 참조).
최종적으로 사용한 솔루션은 다음과 같습니다.
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)
unicodata.normalize 호출은 악센트 문자를 액센트 없이 동등한 문자로 대체하며 단순히 삭제하는 것보다 낫습니다.그런 다음 허용되지 않는 모든 문자가 제거됩니다.
특정 파일 이름 형식에서는 허용되지 않는 파일 이름이 발생할 수 없기 때문에 솔루션에서는 기존의 문자열 앞에 추가되지 않습니다.좀 더 일반적인 해결책이 필요합니다.
한 줄:
valid_file_name = re.sub('[^\w_.)( -]', '', any_string)
읽기 쉽게 하기 위해 '_' 문자를 넣을 수도 있습니다(예를 들어 슬래시를 교체하는 경우).
UNIX 시스템에서는 파일 이름에 대한 제한이 없습니다.
- \0을 포함할 수 없습니다.
- /를 포함할 수 없습니다.
다른 건 다 공정한 게임이에요.
$터치 "> 여러 줄까지> 하하> ^[ [ 31 m red ^ [ 0 m ]>악"$ ls -la-rw-r--r------------------------------------------------------------------------------[31m 빨강?][0m 악]ls - lab-rw-r--r--011월 17일 23:39 \neven \nhaha \n\033 [ 31 m \ red \ 033 \ nevil ]$ perl - e ' ( glob ( q { ) 。/*even*}) {$i; }을(를) 인쇄합니다../짝수 멀티라인ㅎㅎ빨간.사악한
네, ANSI Color Code를 파일명에 저장하여 유효하게 했습니다.
엔터테인먼트를 위해서, 디렉토리명에 BEL 캐릭터를 삽입해, CD에 CD를 삽입했을 때의 재미를 봐 주세요.
re.sub() 메서드를 사용하여 "filelike" 이외의 것을 대체할 수 있습니다.그러나 사실상 모든 문자가 유효할 수 있기 때문에 이를 수행하기 위한 기능은 사전에 구축되어 있지 않다고 생각합니다.
import re
str = "File!name?.txt"
f = open(os.path.join("/tmp", re.sub('[^-a-zA-Z0-9_.() ]+', '', str))
파일이 /tmp/filename으로 처리됩니다.txt를 클릭합니다.
다른 코멘트가 아직 다루지 않은 또 다른 문제는 빈 문자열입니다.빈 문자열은 명백히 유효한 파일 이름이 아닙니다.또한 너무 많은 문자를 제거하여 빈 문자열로 끝날 수도 있습니다.
Windows 의 예약된 파일명과 닷이 있는 문제의 경우, 「임의의 유저 입력으로부터 유효한 파일명을 정규화하는 방법」이라고 하는 질문에 대한 가장 안전한 대답은, 「시도조차 하지 말아 주세요」입니다.데이터베이스의 정수 프라이머리 키를 파일명으로 사용하는 등, 피할 수 있는 방법이 있으면, 그렇게 해 주세요.
파일 확장자에 공백과 '.'를 이름의 일부로 사용해야 하는 경우 다음과 같이 시도해 보십시오.
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
이마저도, 특히 예기치 않은 OS에서는 올바르게 보증할 수 없습니다.예를 들어, RISC OS는 공간을 싫어해 디렉토리 구분자로 「.」를 사용합니다.
그래도 조심해야죠.라틴어만 보고 있다면 인트로에 명확하게 나와 있지 않습니다.ASCII 문자만으로 삭제하면 의미가 없어지거나 다른 의미가 될 수 있습니다.
당신이 포레 포에시(forét poésie)를 가지고 있다고 상상해 보세요. 당신의 소독은 "포트 포시"(강력+무의미한 것)를 줄 수 있습니다.
한자를 상대해야 한다면 더 안좋다.
시스템이 '---'를 하게 될 수도 있지만, 시간이 지나면 실패하게 되어 별로 도움이 되지 않습니다.따라서 파일만 취급하는 경우, 그것들을 자신이 제어하는 범용 체인이라고 부르거나 문자를 그대로 유지하는 것이 좋습니다.URI의 경우도 거의 동일합니다.
"osopen"을 테스트/제외로 포장하여 기본 OS가 파일이 유효한지 여부를 분류하도록 하는 것은 어떨까요?
이것은 작업이 훨씬 적은 것 같고 어떤 OS를 사용하든 유효합니다.
>>> 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'
빈 문자열, 특수 파일 이름('nul', 'con' 등)은 처리하지 않습니다.
많은 답변이 있다는 것을 알고 있습니다만, 대부분은 정규 표현이나 외부 모듈에 의존하고 있기 때문에, 저 자신의 답변을 제출하고 싶습니다.외부 모듈이 필요 없고 정규식이 사용되지 않는 순수 파이썬 함수입니다.잘못된 문자를 지우는 것이 아니라 유효한 문자만 허용하는 방법입니다.
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
만의 유효한 를 넣을 수 .validchars
영어 알파벳에 존재하지 않는 국가 문자 등 시작 부분에 변수가 있습니다.로않는 , ASC 의 파일 시스템, UTF-8 에 가 있는 경우가 .ASC 에 대해서는, ASC 에 가 있는 .2인치
이 함수는 단일 파일 이름의 유효성을 테스트하기 위해 경로 구분 기호를 잘못된 문자로 간주하여 대체합니다.하고 싶을 요.if
separatoros 를 합니다.
나는 여기서 python-slugify 접근법을 좋아했지만 그것은 또한 원하지 않는 점들을 제거하는 것이었다.따라서 다음과 같이 클린 파일명을 s3에 업로드 할 수 있도록 최적화했습니다.
pip install python-slugify
코드 예:
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
출력:
>>> clean_filename
'very-unsafe-file-name-haha.txt'
세이프입니다.하지 않고 할 수 있습니다.또, 하지 않은 문자의 으로는 「」, 「」, 「」, 「」, 「」, 「」, 「」, 「」, 「」, 「」, 「」, 「」, 「」, 「」, 「」(「」)에도 사용할 수 .none
here here here 、 、 here 、 [ 。
패키지를 인스톨 해도 괜찮으시다면, https://pypi.org/project/pathvalidate/ 를 참조해 주세요.
https://pypi.org/project/pathvalidate/ 에서 #sysize-a-syslog :
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")
산출량
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
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)
같은 문제에 직면했을 때 python-slugify를 사용했습니다.
Shoham도 사용법을 제안했지만 therealmarv가 지적했듯이 기본적으로 python-slugify도 점을 변환합니다.
수 .regex_pattern
★★★★★★ 。
> filename = "This is a väryì' Strange File-Nömé.jpeg"
> pattern = re.compile(r'[^-a-zA-Z0-9.]+')
> slugify(filename,regex_pattern=pattern)
'this-is-a-varyi-strange-file-nome.jpeg'
regex 패턴이 에서 복사된 것에 주의해 주세요.
ALLOWED_CHARS_PATTERN_WITH_UPPERCASE
in " " の " の within global 。slugify.py
mapify"로 되었습니다.
.()
한다\
.
하려면 , 「」를 합니다.lowercase=False
★★★★★★ 。
> filename = "This is a väryì' Strange File-Nömé.jpeg"
> pattern = re.compile(r'[^-a-zA-Z0-9.]+')
> slugify(filename,regex_pattern=pattern, lowercase=False)
'This-is-a-varyi-Strange-File-Nome.jpeg'
이것은 Python 3.8.4와 python-slugify 4.0.1을 사용하여 동작합니다.
이러한 솔루션의 대부분은 기능하지 않습니다.
'/hello/world' -> 'hellowold'
'/hellowold' -> 'hellowold'
각 링크의 html을 저장하는 경우 다른 웹 페이지의 html을 덮어쓰게 됩니다.
나는 다음과 같은 받아쓰기를 피클한다.
{'helloworld':
(
{'/hello/world': 'helloworld', '/helloworld/': 'helloworld1'},
2)
}
2는 다음 파일명에 부가되는 번호를 나타냅니다.
나는 매번 dict에서 파일 이름을 찾는다.존재하지 않는 경우는, 필요에 따라서 최대수를 추가해 새로운 것을 작성합니다.
OP가 요구하는 것은 아니지만, 고유하고 되돌릴 수 있는 변환이 필요하기 때문에 사용하는 것은 다음과 같습니다.
# 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+-_ .'))
그 결과는 적어도 sysadmin 관점에서 "어느 정도" 읽을 수 있습니다.
Windows 고유의 패스에 대한 또 다른 해답은 펑키한 모듈을 사용하지 않고 간단한 교환을 사용하는 것입니다.
import re
def check_for_illegal_char(input_str):
# remove illegal characters for Windows file names/paths
# (illegal filenames are a superset (41) of the illegal path names (36))
# this is according to windows blacklist obtained with Powershell
# from: https://stackoverflow.com/questions/1976007/what-characters-are-forbidden-in-windows-and-linux-directory-names/44750843#44750843
#
# PS> $enc = [system.Text.Encoding]::UTF8
# PS> $FileNameInvalidChars = [System.IO.Path]::GetInvalidFileNameChars()
# PS> $FileNameInvalidChars | foreach { $enc.GetBytes($_) } | Out-File -FilePath InvalidFileCharCodes.txt
illegal = '\u0022\u003c\u003e\u007c\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\u0008' + \
'\u0009\u000a\u000b\u000c\u000d\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015' + \
'\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f\u003a\u002a\u003f\u005c\u002f'
output_str, _ = re.subn('['+illegal+']','_', input_str)
output_str = output_str.replace('\\','_') # backslash cannot be handled by regex
output_str = output_str.replace('..','_') # double dots are illegal too, or at least a bad idea
output_str = output_str[:-1] if output_str[-1] == '.' else output_str # can't have end of line '.'
if output_str != input_str:
print(f"The name '{input_str}' had invalid characters, "
f"name was modified to '{output_str}'")
return output_str
로 테스트하는 경우check_for_illegal_char('fas\u0003\u0004good\\..asd.')
이해했습니다.
The name 'fas♥♦good\..asd.' had invalid characters, name was modified to 'fas__good__asd'
루핑하고 있는 문자열을 수정하기 때문에 좋은 답변은 아닐 것입니다만, 정상적으로 동작하고 있는 것 같습니다.
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, '')
갱신하다
이 6년 된 답변에서는 모든 링크가 수리할 수 없을 정도로 끊어졌습니다.
그리고 저도 이제 이런 식으로 하지 않을 거예요base64
안전하지 않은 문자를 인코딩 또는 드롭합니다.Python 3의 예:
import re
t = re.compile("[a-zA-Z0-9.,_-]")
unsafe = "abc∂éåß®∆˚˙©¬ñ√ƒµ©∆∫ø"
safe = [ch for ch in unsafe if t.match(ch)]
# => 'abc'
와 함께base64
인코딩 및 디코딩이 가능하기 때문에 원래 파일 이름을 다시 가져올 수 있습니다.
그러나 사용 사례에 따라서는 랜덤 파일 이름을 생성하고 메타데이터를 별도의 파일 또는 DB에 저장하는 것이 더 나을 수 있습니다.
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'
원래 Link Roten 답변:
그bobcat
프로젝트에는 이 작업을 수행하는 파이썬 모듈이 포함되어 있습니다.
완전히 견고하지는 않습니다.이 투고와 이 회신을 참조해 주세요.
기재한 바와 같이:base64
가독성이 중요하지 않다면 인코딩이 더 나을 수 있습니다.
- 문서 https://svn.origo.ethz.ch/bobcat/src-doc/safefilename-module.html
- 출처: https://svn.origo.ethz.ch/bobcat/trunk/src/bobcatlib/safefilename.py
여기, 이게 모든 기본을 커버할 겁니다.문자 치환을 포함한 모든 유형의 문제를 처리합니다.
Windows, *nix 및 기타 거의 모든 파일 시스템에서 작동합니다.인쇄 가능한 문자만 허용합니다.
def txt2filename(txt, chr_set='normal'):
"""Converts txt to a valid Windows/*nix filename with printable characters only.
args:
txt: The str to convert.
chr_set: 'normal', 'universal', or 'inclusive'.
'universal': ' -.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
'normal': Every printable character exept those disallowed on Windows/*nix.
'extended': All 'normal' characters plus the extended character ASCII codes 128-255
"""
FILLER = '-'
# Step 1: Remove excluded characters.
if chr_set == 'universal':
# Lookups in a set are O(n) vs O(n * x) for a str.
printables = set(' -.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz')
else:
if chr_set == 'normal':
max_chr = 127
elif chr_set == 'extended':
max_chr = 256
else:
raise ValueError(f'The chr_set argument may be normal, extended or universal; not {chr_set=}')
EXCLUDED_CHRS = set(r'<>:"/\|?*') # Illegal characters in Windows filenames.
EXCLUDED_CHRS.update(chr(127)) # DEL (non-printable).
printables = set(chr(x)
for x in range(32, max_chr)
if chr(x) not in EXCLUDED_CHRS)
result = ''.join(x if x in printables else FILLER # Allow printable characters only.
for x in txt)
# Step 2: Device names, '.', and '..' are invalid filenames in Windows.
DEVICE_NAMES = 'CON,PRN,AUX,NUL,COM1,COM2,COM3,COM4,' \
'COM5,COM6,COM7,COM8,COM9,LPT1,LPT2,' \
'LPT3,LPT4,LPT5,LPT6,LPT7,LPT8,LPT9,' \
'CONIN$,CONOUT$,..,.'.split() # This list is an O(n) operation.
if result in DEVICE_NAMES:
result = f'-{result}-'
# Step 3: Maximum length of filename is 255 bytes in Windows and Linux (other *nix flavors may allow longer names).
result = result[:255]
# Step 4: Windows does not allow filenames to end with '.' or ' ' or begin with ' '.
result = re.sub(r'^[. ]', FILLER, result)
result = re.sub(r' $', FILLER, result)
return result
이 솔루션에는 외부 라이브러리가 필요하지 않습니다.또한 인쇄 불가능한 파일 이름을 대체하기도 합니다. 이는 파일 이름이 항상 다루기 쉬운 것은 아니기 때문입니다.
언급URL : https://stackoverflow.com/questions/295135/turn-a-string-into-a-valid-filename
'programing' 카테고리의 다른 글
https://bower.herokuapp.com/packages/에 대한 EINVRES 요구가 502로 실패했습니다. (0) | 2022.10.21 |
---|---|
Vue 구성 요소의 Laravel 로그아웃 경로 (0) | 2022.10.21 |
키로 어레이 값 가져오기 (0) | 2022.10.11 |
MySQL 테이블, 인덱스 및 데이터 복제 (0) | 2022.10.11 |
SELECT 실행 중...위치..."MySQLdb를 사용하여 입력..." (0) | 2022.10.11 |