"""Filename matching with shell patterns.
fnmatch(FILENAME, PATTERN) matches according to the local convention.
fnmatchcase(FILENAME, PATTERN) always takes case in account.
The functions operate by translating the pattern into a regular
expression. They cache the compiled regular expressions for speed.
The function translate(PATTERN) returns a regular expression
corresponding to PATTERN. (It does not compile it.)
__all__ = ["filter", "fnmatch", "fnmatchcase", "translate"]
"""Clear the pattern cache"""
"""Test whether FILENAME matches PATTERN.
Patterns are Unix shell style:
? matches any single character
[seq] matches any character in seq
[!seq] matches any char not in seq
An initial period in FILENAME is not special.
Both FILENAME and PATTERN are first case-normalized
if the operating system requires it.
If you don't want this, use fnmatchcase(FILENAME, PATTERN).
name = os.path.normcase(name)
pat = os.path.normcase(pat)
return fnmatchcase(name, pat)
"""Return the subset of the list NAMES that match PAT"""
pat=os.path.normcase(pat)
if len(_cache) >= _MAXCACHE:
_cache[pat] = re_pat = re.compile(res)
# normcase on posix is NOP. Optimize it away from the loop.
if match(os.path.normcase(name)):
def fnmatchcase(name, pat):
"""Test whether FILENAME matches PATTERN, including case.
This is a version of fnmatch() which doesn't case-normalize
if len(_cache) >= _MAXCACHE:
_cache[pat] = re_pat = re.compile(res)
return re_pat.match(name) is not None
"""Translate a shell PATTERN to a regular expression.
There is no way to quote meta-characters.
if j < n and pat[j] == '!':
if j < n and pat[j] == ']':
while j < n and pat[j] != ']':
stuff = pat[i:j].replace('\\','\\\\')
res = '%s[%s]' % (res, stuff)