我希望能够将glob
格式的模式匹配到字符串列表,而不是文件系统中的实际文件。有什么方法可以做到这一点,或将glob
模式轻松转换为正则表达式吗?
好艺术家复制品;伟大的艺术家glob
。
我偷了;)
steal分别将小球fnmatch.translate
和?
转换为正则表达式*
和.
。我没有调整。
.*
这一个import re
def glob2re(pat):
"""Translate a shell PATTERN to a regular expression.
There is no way to quote meta-characters.
"""
i, n = 0, len(pat)
res = ''
while i < n:
c = pat[i]
i = i+1
if c == '*':
#res = res + '.*'
res = res + '[^/]*'
elif c == '?':
#res = res + '.'
res = res + '[^/]'
elif c == '[':
j = i
if j < n and pat[j] == '!':
j = j+1
if j < n and pat[j] == ']':
j = j+1
while j < n and pat[j] != ']':
j = j+1
if j >= n:
res = res + '\\['
else:
stuff = pat[i:j].replace('\\','\\\\')
i = j+1
if stuff[0] == '!':
stuff = '^' + stuff[1:]
elif stuff[0] == '^':
stuff = '\\' + stuff
res = '%s[%s]' % (res, stuff)
else:
res = res + re.escape(c)
return res + '\Z(?ms)'
,fnmatch.filter
和re.match
都起作用。
re.search
在此页面上找到的Glob模式和字符串通过测试。
def glob_filter(names,pat):
return (name for name in names if re.match(glob2re(pat),name))
pat_dict = {
'a/b/*/f.txt': ['a/b/c/f.txt', 'a/b/q/f.txt', 'a/b/c/d/f.txt','a/b/c/d/e/f.txt'],
'/foo/bar/*': ['/foo/bar/baz', '/spam/eggs/baz', '/foo/bar/bar'],
'/*/bar/b*': ['/foo/bar/baz', '/foo/bar/bar'],
'/*/[be]*/b*': ['/foo/bar/baz', '/foo/bar/bar'],
'/foo*/bar': ['/foolicious/spamfantastic/bar', '/foolicious/bar']
}
for pat in pat_dict:
print('pattern :\t{}\nstrings :\t{}'.format(pat,pat_dict[pat]))
print('matched :\t{}\n'.format(list(glob_filter(pat_dict[pat],pat))))
模块将glob
用于单个路径元素。
这意味着路径分为目录名和文件名,如果目录名包含元字符(包含字符fnmatch
module,fnmatch
或[
中的任何字符),则将它们扩展递归] >。
如果您有简单文件名的字符串列表,那么仅使用*
就足够了:
?
但是如果它们包含完整路径,您需要做更多的工作,因为生成的正则表达式不会考虑路径段(通配符不会排除分隔符,也不会针对跨平台路径匹配进行调整)。
您可以从路径构造一个简单的fnmatch.filter()
function,然后将其与之匹配:
fnmatch.filter()
这个满口可以使用路径上任意位置的glob快速找到匹配项:
import fnmatch
matching = fnmatch.filter(filenames, pattern)
在Python 3.4+上,您只能使用trie。
虽然pathlib.PurePath(path_string).match(pattern)
可直接用于检查模式是否与文件名匹配,但是您也可以使用pathlib
from PyPI方法从给定的pathlib
模式中生成正则表达式:
没关系,我找到了。我需要fnmatch.fnmatch
模块。
@ Veedrac fnmatch.translate
答案的扩展名,可以应用于字符串列表: