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

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

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


当前回答

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

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

其他回答

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

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

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

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

你可以使用re.sub()方法替换任何非“类文件”的东西。但实际上,每个字符都可以是有效的;所以没有预先构建的函数(我相信)来完成它。

import re

str = "File!name?.txt"
f = open(os.path.join("/tmp", re.sub('[^-a-zA-Z0-9_.() ]+', '', str))

将导致/tmp/filename.txt的文件句柄。

不过你得小心点。如果你只看拉丁语言,在你的介绍中没有清楚地说出来。如果您仅使用ascii字符对某些单词进行消毒,它们可能会变得毫无意义或具有其他含义。

假设你有“forêt poésie”(森林诗歌),你的消毒可能会给“堡垒-posie”(强大+无意义的东西)

如果你必须处理汉字,那就更糟了。

“下北沢”您的系统可能最终会执行“——”,这注定会在一段时间后失败,而且没有多大帮助。因此,如果您只处理文件,我建议您将它们称为您控制的通用链,或者保持字符原样。对于uri,大致相同。

你可以看看Django框架(但要考虑到许可!),看看他们如何从任意文本中创建一个“slug”。段代码是URL和文件名友好的。

Django文本utils定义了一个函数,slugify(),这可能是这种事情的黄金标准。本质上,他们的代码如下。

import unicodedata
import re

def slugify(value, allow_unicode=False):
    """
    Taken from https://github.com/django/django/blob/master/django/utils/text.py
    Convert to ASCII if 'allow_unicode' is False. Convert spaces or repeated
    dashes to single dashes. Remove characters that aren't alphanumerics,
    underscores, or hyphens. Convert to lowercase. Also strip leading and
    trailing whitespace, dashes, and underscores.
    """
    value = str(value)
    if allow_unicode:
        value = unicodedata.normalize('NFKC', value)
    else:
        value = unicodedata.normalize('NFKD', value).encode('ascii', 'ignore').decode('ascii')
    value = re.sub(r'[^\w\s-]', '', value.lower())
    return re.sub(r'[-\s]+', '-', value).strip('-_')

旧版本是:

def slugify(value):
    """
    Normalizes string, converts to lowercase, removes non-alpha characters,
    and converts spaces to hyphens.
    """
    import unicodedata
    value = unicodedata.normalize('NFKD', value).encode('ascii', 'ignore')
    value = unicode(re.sub('[^\w\s-]', '', value).strip().lower())
    value = unicode(re.sub('[-\s]+', '-', value))
    # ...
    return value

还有更多,但我把它省略了,因为它没有解决怠惰,而是逃避。