我有一个字符串,我想用它作为文件名,所以我想用Python删除文件名中不允许的所有字符。
我宁愿严格一点,所以假设我想只保留字母、数字和一小组其他字符,如“_-.()”。”。最优雅的解决方案是什么?
文件名需要在多个操作系统(Windows, Linux和Mac OS)上有效——它是我库中的一个MP3文件,以歌曲标题为文件名,并在3台机器之间共享和备份。
我有一个字符串,我想用它作为文件名,所以我想用Python删除文件名中不允许的所有字符。
我宁愿严格一点,所以假设我想只保留字母、数字和一小组其他字符,如“_-.()”。”。最优雅的解决方案是什么?
文件名需要在多个操作系统(Windows, Linux和Mac OS)上有效——它是我库中的一个MP3文件,以歌曲标题为文件名,并在3台机器之间共享和备份。
当前回答
仍然没有找到一个好的库来生成有效的文件名。注意,在德语、挪威语或法语等语言中,文件名中的特殊字符非常常见,完全可以接受。所以我最终有了自己的图书馆:
# util/files.py
CHAR_MAX_LEN = 31
CHAR_REPLACE = '_'
ILLEGAL_CHARS = [
'#', # pound
'%', # percent
'&', # ampersand
'{', # left curly bracket
'}', # right curly bracket
'\\', # back slash
'<', # left angle bracket
'>', # right angle bracket
'*', # asterisk
'?', # question mark
'/', # forward slash
' ', # blank spaces
'$', # dollar sign
'!', # exclamation point
"'", # single quotes
'"', # double quotes
':', # colon
'@', # at sign
'+', # plus sign
'`', # backtick
'|', # pipe
'=', # equal sign
]
def generate_filename(
name, char_replace=CHAR_REPLACE, length=CHAR_MAX_LEN,
illegal=ILLEGAL_CHARS, replace_dot=False):
''' return clean filename '''
# init
_elem = name.split('.')
extension = _elem[-1].strip()
_length = length - len(extension) - 1
label = '.'.join(_elem[:-1]).strip()[:_length]
filename = ''
# replace '.' ?
if replace_dot:
label = label.replace('.', char_replace)
# clean
for char in label + '.' + extension:
if char in illegal:
char = char_replace
filename += char
return filename
generate_虚构(“nucgae zutaaer .0.1 docx”,replace_dot=False)
nucgae_zutaäer..0.1.docx
generate_虚构(“nucgae zutaaer .0.1 docx”,replace_dot=True)
nucgae_zutaäer__0_1.docx
其他回答
其他注释还没有解决的另一个问题是空字符串,这显然不是一个有效的文件名。你也可能因为剥离太多字符而得到一个空字符串。
对于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
即使这样也不能保证正确,特别是在意想不到的操作系统上-例如RISC操作系统讨厌空格并使用'。'作为目录分隔符。
如果你不介意安装一个包,这应该是有用的: https://pypi.org/project/pathvalidate/
从https://pypi.org/project/pathvalidate/ # sanitize-a-filename:
来自您的插件信息 fname =菲:l * e / p \ " a ? t < t > h |。xt” 打印(f“fname) -> (sanitize_filename, fname) fname =“\0_a*b:c<d>e%f/(g)h+i_0.txt” 打印(f“fname) -> (sanitize_filename, fname) 输出 菲:洛杉矶* e - p”? t > h |。<xt ->档案 _a*b:c<d>e%f/(g)h+i_0.txt -> _abcde%f(g)h+i_0.txt
不完全是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+-_ .'))
结果“有些”可读,至少从系统管理员的角度来看是这样。
请记住,在Unix系统上实际上没有文件名限制
它可能不包含\0 它可能不包含/
其他一切都是公平的。
$ touch " > even multiline > haha > ^[[31m red ^[[0m > evil" $ ls -la -rw-r--r-- 0 Nov 17 23:39 ?even multiline?haha??[31m red ?[0m?evil $ ls -lab -rw-r--r-- 0 Nov 17 23:39 \neven\ multiline\nhaha\n\033[31m\ red\ \033[0m\nevil $ perl -e 'for my $i ( glob(q{./*even*}) ){ print $i; } ' ./ even multiline haha red evil
是的,我只是将ANSI颜色代码存储在一个文件名中,并使它们生效。
为了娱乐,在目录名中放入一个BEL字符,并观看当您CD到其中时所产生的乐趣;)
>>> 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'等)。