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

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

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


当前回答

其他注释还没有解决的另一个问题是空字符串,这显然不是一个有效的文件名。你也可能因为剥离太多字符而得到一个空字符串。

对于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操作系统讨厌空格并使用'。'作为目录分隔符。

其他回答

为什么不直接用try/except来包装“osopen”,让底层操作系统来判断文件是否有效?

这看起来工作量少得多,而且无论您使用哪种操作系统都是有效的。

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

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

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

其他注释还没有解决的另一个问题是空字符串,这显然不是一个有效的文件名。你也可能因为剥离太多字符而得到一个空字符串。

对于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操作系统讨厌空格并使用'。'作为目录分隔符。

大多数解决方案都不起作用。

“你好/世界”——>“你好世界”

“/helloworld”/ ->“helloworld”

这通常不是你想要的,比如说你要为每个链接保存html,你要为不同的网页覆盖html。

我腌字典,如:

{'helloworld': 
    (
    {'/hello/world': 'helloworld', '/helloworld/': 'helloworld1'},
    2)
    }

2表示应该追加到下一个文件名的数字。

我每次都从字典中查找文件名。如果它不在那里,我创建一个新的,如果需要追加最大的数字。