我有一个字符串,我想用它作为文件名,所以我想用Python删除文件名中不允许的所有字符。

我宁愿严格一点,所以假设我想只保留字母、数字和一小组其他字符,如“_-.()”。”。最优雅的解决方案是什么?

文件名需要在多个操作系统(Windows, Linux和Mac OS)上有效——它是我库中的一个MP3文件,以歌曲标题为文件名,并在3台机器之间共享和备份。


当前回答

我相信这不是一个很好的答案,因为它修改了它循环的字符串,但它似乎工作得很好:

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, '')

其他回答

您可以将列表推导式与字符串方法一起使用。

>>> s
'foo-bar#baz?qux@127/\\9]'
>>> "".join(x for x in s if x.isalnum())
'foobarbazqux1279'

使用字符串作为文件名的原因是什么?如果人类的可读性不是一个因素,我会使用base64模块,它可以产生文件系统安全字符串。它是不可读的,但你不需要处理碰撞,而且它是可逆的。

import base64
file_name_string = base64.urlsafe_b64encode(your_string)

更新:根据Matthew的评论修改。

如果你不介意安装一个包,这应该是有用的: 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

一句话:

valid_file_name = re.sub('[^\w_.)( -]', '', any_string)

你也可以用“_”字符让它更具可读性(例如替换斜杠)

我喜欢这里的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)。