Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/regex/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 是否可以将fnmatch.translate(“***.py”)转换为语义正确的正则表达式?_Python_Regex - Fatal编程技术网

Python 是否可以将fnmatch.translate(“***.py”)转换为语义正确的正则表达式?

Python 是否可以将fnmatch.translate(“***.py”)转换为语义正确的正则表达式?,python,regex,Python,Regex,是否有任何简单的方法(或可能的方法)将fnmatch.translate的输出转换为匹配零个或多个目录的正则表达式 >>> import fnmatch >>> fnmatch.translate("**/*.py") '.*.*\\/.*\\.py\\Z(?ms)' 我想要的是放在中的正则表达式片段 dirs = ['a.py', 'b/a.py', 'b/c/a.py', 'b/c/d/a.py'] r = fnmatch.translate("**/*

是否有任何简单的方法(或可能的方法)将
fnmatch.translate
的输出转换为匹配零个或多个目录的正则表达式

>>> import fnmatch
>>> fnmatch.translate("**/*.py")
'.*.*\\/.*\\.py\\Z(?ms)'
我想要的是放在
中的正则表达式片段

dirs = ['a.py', 'b/a.py', 'b/c/a.py', 'b/c/d/a.py']
r = fnmatch.translate("**/*.py").replace(".*.*", "___")
所以

[d for d in dirs if re.match(r, d)] == dirs
此尝试在前两种情况下不匹配:

fnmatch.translate("**/*.py").replace('.*.*', "(.*/.*)*")
这与第一个不匹配:

fnmatch.translate("**/*.py").replace('.*.*', "(.*/?)*")
这让口译员很难受:

fnmatch.translate("**/*.py").replace('.*.*', "(.*|(.*/.*))*")
我很乐意得到一个解释为什么不可能的答案

更新:仅用空字符串替换
***/
不起作用:

dirs = ['a.py', 'b/a.py', 'b/c/a.py', 'b/c/d/a.py']

def translate(pat, repl=None):
    r = fnmatch.translate(pat)
    if repl:
        r = r.replace(".*.*", repl)
    r = re.compile(r)
    return [d for d in dirs if r.match(d)]

>>> print translate("**/*.py".replace("**/", ""))
['a.py', 'b/a.py', 'b/c/a.py', 'b/c/d/a.py']  # correct
>>> print translate("b/**/*.py".replace("**/", ""))
['b/a.py', 'b/c/a.py', 'b/c/d/a.py']  # correct
>>> print translate("b/**/b.py".replace("**/", ""))
['b/a.py']  # incorrect
实际上——除了一个
*
之外,您根本不需要更改
*
;相反,您需要将单个未配对的
*
更改为
[^/]*

因此,实际需要的转换表是——根本不使用
fnmatch.translate()
,而是自己滚动:

`?` -> `.`
`.` -> `[.]`
`**/` -> `(?:.*/)?`
`*` -> `[^/]*`
正确处理
[!foo]
及其类似的操作最好是从上游
翻译
代码复制逻辑


应用这些规则将
***.py
转换为
(?:.*/)?[^/]*[.]py
,这与问题中的所有四个名称匹配:

>>> import re
>>> dirs = ['a.py', 'b/a.py', 'b/c/a.py', 'b/c/d/a.py']
>>> py_re = re.compile('(?:.*/)?[^/]*[.]py')
>>> [ 'Matches' if py_re.match(x) else 'Non-Matching' for x in dirs ]
['Matches', 'Matches', 'Matches', 'Matches']

转换的一个实现:

def build_re(glob_str):
    opts = re.compile('([.]|[*][*]/|[*]|[?])|(.)')
    out = ''
    for (pattern_match, literal_text) in opts.findall(glob_str):
        if pattern_match == '.':
            out += '[.]'
        elif pattern_match == '**/':
            out += '(?:.*/)?'
        elif pattern_match == '*':
            out += '[^/]*'
        elif pattern_match == '?':
            out += '.'
        elif literal_text:
            out += literal_text
    return out
实际上——除了一个
*
之外,您根本不需要更改
*
;相反,您需要将单个未配对的
*
更改为
[^/]*

因此,实际需要的转换表是——根本不使用
fnmatch.translate()
,而是自己滚动:

`?` -> `.`
`.` -> `[.]`
`**/` -> `(?:.*/)?`
`*` -> `[^/]*`
正确处理
[!foo]
及其类似的操作最好是从上游
翻译
代码复制逻辑


应用这些规则将
***.py
转换为
(?:.*/)?[^/]*[.]py
,这与问题中的所有四个名称匹配:

>>> import re
>>> dirs = ['a.py', 'b/a.py', 'b/c/a.py', 'b/c/d/a.py']
>>> py_re = re.compile('(?:.*/)?[^/]*[.]py')
>>> [ 'Matches' if py_re.match(x) else 'Non-Matching' for x in dirs ]
['Matches', 'Matches', 'Matches', 'Matches']

转换的一个实现:

def build_re(glob_str):
    opts = re.compile('([.]|[*][*]/|[*]|[?])|(.)')
    out = ''
    for (pattern_match, literal_text) in opts.findall(glob_str):
        if pattern_match == '.':
            out += '[.]'
        elif pattern_match == '**/':
            out += '(?:.*/)?'
        elif pattern_match == '*':
            out += '[^/]*'
        elif pattern_match == '?':
            out += '.'
        elif literal_text:
            out += literal_text
    return out

这里是Charles翻译算法的非正则表达式实现

更新1:此版本处理前导的

更新2:以
fnmatch
的方式处理否定有点复杂(基本上
fnmatch
处理
[!…]
类似于正则表达式
[^…]
):

def翻译(pat):
r=“”
i=0
L=len(pat)
而我\[\!\]
j+=1
而j=L:
r+='\\['\\\未找到结束']',回溯
其他:
stuff=pat[i:j].替换('\\','\\\')
i=j+1
如果stuff[0]=='!':
stuff='^'+stuff[1:#翻译否定
elif stuff[0]='^':
stuff='\\'+stuff#引号^character
r='%s[%s]'%(r,stuff)
其他:
r+=重新逃逸(帕特[i])
#r+=pat[i]
i+=1
r+='\\Z(?ms)'
返回r

(否定码几乎是从fnmatch中一字不差地偷走的。)

这里是Charles翻译算法的非正则表达式实现

更新1:此版本处理前导的

更新2:以
fnmatch
的方式处理否定有点复杂(基本上
fnmatch
处理
[!…]
类似于正则表达式
[^…]
):

def翻译(pat):
r=“”
i=0
L=len(pat)
而我\[\!\]
j+=1
而j=L:
r+='\\['\\\未找到结束']',回溯
其他:
stuff=pat[i:j].替换('\\','\\\')
i=j+1
如果stuff[0]=='!':
stuff='^'+stuff[1:#翻译否定
elif stuff[0]='^':
stuff='\\'+stuff#引号^character
r='%s[%s]'%(r,stuff)
其他:
r+=重新逃逸(帕特[i])
#r+=pat[i]
i+=1
r+='\\Z(?ms)'
返回r

(否定码几乎是从fnmatch.一字不差地偷走的)

为什么不
fnmatch.translate(“*.py”)
?因为这不允许例如
“b/**/*.py”
,即
b
下的所有.py文件(dirs
中的最后三项)。
b/*.py
将具有相同的效果,由于
*
存在隐式
**
。它允许
foo
下的所有
.py
文件。尝试
pattern=pattern.replace(“***/”,”)
。这对
“b/***/a.py”
不起作用。为什么不
fnmatch.translate(“*.py”)
?因为这不允许例如
“b/***.py”
,即
b下的所有.py文件