Rem*_*emi 67
蟒蛇:
"".join([c for c in filename if c.isalpha() or c.isdigit() or c==' ']).rstrip()
Run Code Online (Sandbox Code Playgroud)
这接受Unicode字符,但删除换行符等.
例:
filename = u"ad\nbla'{-+\)(ç?"
Run Code Online (Sandbox Code Playgroud)
得到: adblaç
编辑 str.isalnum()在一步上做字母数字. - 来自下面的queueoverflow的评论.danodonovan暗示要保持一个点.
keepcharacters = (' ','.','_')
"".join(c for c in filename if c.isalnum() or c in keepcharacters).rstrip()
Run Code Online (Sandbox Code Playgroud)
Mit*_*ers 12
我不建议使用任何其他答案。它们臃肿,使用糟糕的技术,并替换了大量的合法字符(有些甚至删除了所有 Unicode 字符,这很疯狂,因为它们在文件名中是合法的)。其中一些甚至只是为了这个微小而简单的工作而导入巨大的库......这太疯狂了。
这是一个正则表达式单行代码,它可以有效地替换每个非法文件系统字符,而不是其他字符。没有库,没有膨胀,只有一个简单命令中的完全合法的文件名。
参考: https: //en.wikipedia.org/wiki/Filename#Reserved_characters_and_words
正则表达式:
clean = re.sub(r"[/\\?%*:|\"<>\x7F\x00-\x1F]", "-", dirty)
Run Code Online (Sandbox Code Playgroud)
用法:
import re
# Here's a dirty, illegal filename full of control-characters and illegal chars.
dirty = "".join(["\\[/\\?%*:|\"<>0x7F0x00-0x1F]", chr(0x1F) * 15])
# Clean it in one fell swoop.
clean = re.sub(r"[/\\?%*:|\"<>\x7F\x00-\x1F]", "-", dirty)
# Result: "-[----------0x7F0x00-0x1F]---------------"
print(clean)
Run Code Online (Sandbox Code Playgroud)
这是一个极端的例子,几乎每个字符都是非法的,因为我们使用正则表达式删除的相同字符列表构建了脏字符串,我们甚至在末尾填充了一堆“0x1F(ascii 31)”只是为了显示它还删除了非法控制字符。
就是这个。这个正则表达式是您需要的唯一答案。它处理现代文件系统(Mac、Windows 和 Linux)上的所有非法字符。删除超出此范围的任何内容都属于“美化”类别,与制作合法的磁盘文件名无关。
Windows 用户的更多工作:
运行此命令后,您还可以选择根据 Windows 上的“特殊设备名称”列表(不区分大小写的单词列表,例如“CON”、“AUX”、“COM0”等)检查结果。
可以在https://en.wikipedia.org/wiki/Filename#Comparison_of_filename_limitations中找到NTFS和FAT文件系统的“保留字”和“注释”列中的非法字。
仅当您计划将文件存储在 NTFS 或 FAT 类型的磁盘上时,才需要过滤保留字。因为Windows保留了某些“神奇文件名”供内部使用。它保留它们时不区分大小写,并且不关心扩展名,这意味着例如在 Windows 上aux.c
是非法文件名(非常愚蠢)。
所有 Mac/Linux 文件系统都没有这样的愚蠢限制,因此如果您使用的是良好的文件系统,则无需执行任何其他操作。哎呀,事实上,我们在正则表达式中过滤掉的大多数“非法字符”都是 Windows 特定的限制。Mac/Linux 文件系统可以存储其中的大部分。但我们无论如何都会过滤它们,因为它使文件名可移植到 Windows 计算机。
Ngu*_*aga 11
我的要求是保守的(生成的文件名需要在多个操作系统上有效,包括一些古老的移动操作系统).我结束了:
"".join([c for c in text if re.match(r'\w', c)])
Run Code Online (Sandbox Code Playgroud)
该白色列出了字母数字字符(az,AZ,0-9)和下划线.如果要匹配很多字符串,则可以编译和缓存正则表达式以提高效率.就我而言,它不会产生任何重大影响.
或多或少在这里提到的正则表达式,但反过来(替换任何未列出的):
>>> import re
>>> filename = u"ad\nbla'{-+\)(ç1?"
>>> re.sub(r'[^\w\d-]','_',filename)
u'ad_bla__-_____1_'
Run Code Online (Sandbox Code Playgroud)
这里有一些合理的答案,但就我而言,我想采用的东西可能是带有空格和标点符号的字符串,而不仅仅是删除它们,我宁愿用下划线代替。即使在大多数操作系统中,空格是允许的文件名字符,它们还是有问题的。另外,在我的情况下,如果原始字符串包含句点,则我不希望该句点传递到文件名中,否则它将生成我可能不希望的“额外扩展名”(我自己添加了扩展名)
def make_safe_filename(s):
def safe_char(c):
if c.isalnum():
return c
else:
return "_"
return "".join(safe_char(c) for c in s).rstrip("_")
print(make_safe_filename( "hello you crazy $#^#& 2579 people!!! : die!!!" ) + ".gif")
Run Code Online (Sandbox Code Playgroud)
印刷品:
hello_you_crazy _______ 2579_people ______ die ___。gif
许多其他答案的问题是它们只处理字符替换;不是其他问题。
这是一个全面的通用解决方案。它为您处理所有类型的问题,包括(但不限于)字符替换。它应该涵盖所有基础。
适用于 Windows、*nix 和几乎所有其他文件系统。
def txt2filename(txt, chr_set='printable'):
"""Converts txt to a valid filename.
Args:
txt: The str to convert.
chr_set:
'printable': Any printable character except those disallowed on Windows/*nix.
'extended': 'printable' + extended ASCII character codes 128-255
'universal': For almost *any* file system. '-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
"""
FILLER = '-'
MAX_LEN = 255 # Maximum length of filename is 255 bytes in Windows and some *nix flavors.
# Step 1: Remove excluded characters.
BLACK_LIST = set(chr(127) + r'<>:"/\|?*') # 127 is unprintable, the rest are illegal in Windows.
white_lists = {
'universal': {'-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'},
'printable': {chr(x) for x in range(32, 127)} - BLACK_LIST, # 0-32, 127 are unprintable,
'extended' : {chr(x) for x in range(32, 256)} - BLACK_LIST,
}
white_list = white_lists[chr_set]
result = ''.join(x
if x in white_list else FILLER
for x in txt)
# Step 2: Device names, '.', and '..' are invalid filenames in Windows.
DEVICE_NAMES = 'CON,PRN,AUX,NUL,COM1,COM2,COM3,COM4,' \
'COM5,COM6,COM7,COM8,COM9,LPT1,LPT2,' \
'LPT3,LPT4,LPT5,LPT6,LPT7,LPT8,LPT9,' \
'CONIN$,CONOUT$,..,.'.split(',') # This list is an O(n) operation.
if result in DEVICE_NAMES:
result = f'{FILLER}{result}{FILLER}'
# Step 3: Truncate long files while preserving the file extension.
if len(result) > MAX_LEN:
if '.' in txt:
result, _, ext = result.rpartition('.')
ext = '.' + ext
else:
ext = ''
result = result[:MAX_LEN - len(ext)] + ext
# Step 4: Windows does not allow filenames to end with '.' or ' ' or begin with ' '.
result = re.sub(r'^[. ]', FILLER, result)
result = re.sub(r' $', FILLER, result)
return result
Run Code Online (Sandbox Code Playgroud)
它会替换不可打印的字符,即使它们在技术上是有效的文件名,因为它们并不总是易于处理。
不需要外部库。
这里没有解决方案,只有您必须考虑的问题:
你的最小最大文件名长度是多少?(例如,DOS 仅支持 8-11 个字符;大多数操作系统不支持 >256 个字符)
在某些情况下禁止哪些文件名?(Windows 仍然不支持将文件另存为CON.TXT
- 请参阅https://blogs.msdn.microsoft.com/oldnewthing/20031022-00/?p=42073)
请记住.
并..
具有特定含义(当前/父目录),因此是不安全的。
是否存在文件名冲突的风险 - 由于删除字符或多次使用相同的文件名?
考虑只对数据进行散列并将其十六进制转储用作文件名?
如果你不介意导入其他包,那么 werkzeug 有一个清理字符串的方法:
from werkzeug.utils import secure_filename
secure_filename("hello.exe")
'hello.exe'
secure_filename("/../../.ssh")
'ssh'
secure_filename("DROP TABLE")
'DROP_TABLE'
#fork bomb on Linux
secure_filename(": () {: |: &} ;:")
''
#delete all system files on Windows
secure_filename("del*.*")
'del'
Run Code Online (Sandbox Code Playgroud)
https://pypi.org/project/Werkzeug/
归档时间: |
|
查看次数: |
29644 次 |
最近记录: |