我有一个字符串,我想用它作为文件名,所以我想用Python删除文件名中不允许的所有字符。
我宁愿严格一点,所以假设我想只保留字母、数字和一小组其他字符,如“_-.()”。”。最优雅的解决方案是什么?
文件名需要在多个操作系统(Windows, Linux和Mac OS)上有效——它是我库中的一个MP3文件,以歌曲标题为文件名,并在3台机器之间共享和备份。
我有一个字符串,我想用它作为文件名,所以我想用Python删除文件名中不允许的所有字符。
我宁愿严格一点,所以假设我想只保留字母、数字和一小组其他字符,如“_-.()”。”。最优雅的解决方案是什么?
文件名需要在多个操作系统(Windows, Linux和Mac OS)上有效——它是我库中的一个MP3文件,以歌曲标题为文件名,并在3台机器之间共享和备份。
当前回答
大多数解决方案都不起作用。
“你好/世界”——>“你好世界”
“/helloworld”/ ->“helloworld”
这通常不是你想要的,比如说你要为每个链接保存html,你要为不同的网页覆盖html。
我腌字典,如:
{'helloworld':
(
{'/hello/world': 'helloworld', '/helloworld/': 'helloworld1'},
2)
}
2表示应该追加到下一个文件名的数字。
我每次都从字典中查找文件名。如果它不在那里,我创建一个新的,如果需要追加最大的数字。
其他回答
大多数解决方案都不起作用。
“你好/世界”——>“你好世界”
“/helloworld”/ ->“helloworld”
这通常不是你想要的,比如说你要为每个链接保存html,你要为不同的网页覆盖html。
我腌字典,如:
{'helloworld':
(
{'/hello/world': 'helloworld', '/helloworld/': 'helloworld1'},
2)
}
2表示应该追加到下一个文件名的数字。
我每次都从字典中查找文件名。如果它不在那里,我创建一个新的,如果需要追加最大的数字。
这是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'
请记住,在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到其中时所产生的乐趣;)
您可以将列表推导式与字符串方法一起使用。
>>> s
'foo-bar#baz?qux@127/\\9]'
>>> "".join(x for x in s if x.isalnum())
'foobarbazqux1279'
这是我最终使用的解决方案:
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)
unicodedata。Normalize调用将重音字符替换为同等的非重音字符,这比简单地将它们剥离要好。之后,所有不允许的字符都将被删除。
我的解决方案没有预先添加一个已知字符串,以避免可能的不允许文件名,因为我知道给定特定的文件名格式,它们不会出现。这需要一个更普遍的解决方案。