我有一个字符串,我想用它作为文件名,所以我想用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中,某些设备名称是保留的。例如,你不能创建一个名为“nul”,“null .txt”(或nul.txt)的文件。)保留的名字是: CON, PRN, AUX, NUL, COM1, COM2, COM3, COM4, COM5, COM6, COM7, COM8, COM9, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, LPT9
您可能可以通过在文件名前添加一些字符串来解决这些问题,这些字符串永远不会导致这些情况之一,并剥离无效字符。
Github上有个不错的项目叫python-slugify:
安装:
pip install python-slugify
然后使用:
>>> from slugify import slugify
>>> txt = "This\ is/ a%#$ test ---"
>>> slugify(txt)
'this-is-a-test'
不过你得小心点。如果你只看拉丁语言,在你的介绍中没有清楚地说出来。如果您仅使用ascii字符对某些单词进行消毒,它们可能会变得毫无意义或具有其他含义。
假设你有“forêt poésie”(森林诗歌),你的消毒可能会给“堡垒-posie”(强大+无意义的东西)
如果你必须处理汉字,那就更糟了。
“下北沢”您的系统可能最终会执行“——”,这注定会在一段时间后失败,而且没有多大帮助。因此,如果您只处理文件,我建议您将它们称为您控制的通用链,或者保持字符原样。对于uri,大致相同。
大多数解决方案都不起作用。
“你好/世界”——>“你好世界”
“/helloworld”/ ->“helloworld”
这通常不是你想要的,比如说你要为每个链接保存html,你要为不同的网页覆盖html。
我腌字典,如:
{'helloworld':
(
{'/hello/world': 'helloworld', '/helloworld/': 'helloworld1'},
2)
}
2表示应该追加到下一个文件名的数字。
我每次都从字典中查找文件名。如果它不在那里,我创建一个新的,如果需要追加最大的数字。
This whitelist approach (ie, allowing only the chars present in valid_chars) will work if there aren't limits on the formatting of the files or combination of valid chars that are illegal (like ".."), for example, what you say would allow a filename named " . txt" which I think is not valid on Windows. As this is the most simple approach I'd try to remove whitespace from the valid_chars and prepend a known valid string in case of error, any other approach will have to know about what is allowed where to cope with Windows file naming limitations and thus be a lot more complex.
>>> 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'