blob: b1c37f59dff0cc3cf89e81e60b24e06d496309c1 [file] [log] [blame]
Guido van Rossum7e4b2de1995-01-27 02:41:45 +00001"""Filename matching with shell patterns.
Guido van Rossum05e52191992-01-12 23:29:29 +00002
Guido van Rossum7e4b2de1995-01-27 02:41:45 +00003fnmatch(FILENAME, PATTERN) matches according to the local convention.
4fnmatchcase(FILENAME, PATTERN) always takes case in account.
Guido van Rossum05e52191992-01-12 23:29:29 +00005
Guido van Rossum7e4b2de1995-01-27 02:41:45 +00006The functions operate by translating the pattern into a regular
7expression. They cache the compiled regular expressions for speed.
8
9The function translate(PATTERN) returns a regular expression
10corresponding to PATTERN. (It does not compile it.)
11"""
12
Guido van Rossum9694fca1997-10-22 21:00:49 +000013import re
14
Raymond Hettinger4a4296e2003-07-13 16:06:26 +000015__all__ = ["filter", "fnmatch","fnmatchcase","translate"]
Skip Montanaroeccd02a2001-01-20 23:34:12 +000016
Guido van Rossum7e4b2de1995-01-27 02:41:45 +000017_cache = {}
R. David Murraybda5f2b2010-07-09 13:29:33 +000018_MAXCACHE = 100
Guido van Rossum762c39e1991-01-01 18:11:14 +000019
Guido van Rossum762c39e1991-01-01 18:11:14 +000020def fnmatch(name, pat):
Tim Peters88869f92001-01-14 23:36:06 +000021 """Test whether FILENAME matches PATTERN.
22
23 Patterns are Unix shell style:
24
25 * matches everything
26 ? matches any single character
27 [seq] matches any character in seq
28 [!seq] matches any char not in seq
29
30 An initial period in FILENAME is not special.
31 Both FILENAME and PATTERN are first case-normalized
32 if the operating system requires it.
33 If you don't want this, use fnmatchcase(FILENAME, PATTERN).
34 """
35
36 import os
37 name = os.path.normcase(name)
38 pat = os.path.normcase(pat)
39 return fnmatchcase(name, pat)
Guido van Rossum7e4b2de1995-01-27 02:41:45 +000040
Martin v. Löwisb5d4d2a2001-06-06 06:24:38 +000041def filter(names, pat):
42 """Return the subset of the list NAMES that match PAT"""
43 import os,posixpath
44 result=[]
45 pat=os.path.normcase(pat)
Raymond Hettinger54f02222002-06-01 14:18:47 +000046 if not pat in _cache:
Martin v. Löwisb5d4d2a2001-06-06 06:24:38 +000047 res = translate(pat)
R. David Murraybda5f2b2010-07-09 13:29:33 +000048 if len(_cache) >= _MAXCACHE:
49 _cache.clear()
Martin v. Löwisb5d4d2a2001-06-06 06:24:38 +000050 _cache[pat] = re.compile(res)
51 match=_cache[pat].match
52 if os.path is posixpath:
53 # normcase on posix is NOP. Optimize it away from the loop.
54 for name in names:
55 if match(name):
56 result.append(name)
57 else:
58 for name in names:
59 if match(os.path.normcase(name)):
60 result.append(name)
61 return result
62
Guido van Rossum7e4b2de1995-01-27 02:41:45 +000063def fnmatchcase(name, pat):
Tim Peters88869f92001-01-14 23:36:06 +000064 """Test whether FILENAME matches PATTERN, including case.
65
66 This is a version of fnmatch() which doesn't case-normalize
67 its arguments.
68 """
69
Raymond Hettinger54f02222002-06-01 14:18:47 +000070 if not pat in _cache:
Tim Peters88869f92001-01-14 23:36:06 +000071 res = translate(pat)
R. David Murraybda5f2b2010-07-09 13:29:33 +000072 if len(_cache) >= _MAXCACHE:
73 _cache.clear()
Tim Peters88869f92001-01-14 23:36:06 +000074 _cache[pat] = re.compile(res)
75 return _cache[pat].match(name) is not None
Guido van Rossum762c39e1991-01-01 18:11:14 +000076
Guido van Rossum05e52191992-01-12 23:29:29 +000077def translate(pat):
Tim Peters88869f92001-01-14 23:36:06 +000078 """Translate a shell PATTERN to a regular expression.
79
80 There is no way to quote meta-characters.
81 """
82
83 i, n = 0, len(pat)
84 res = ''
85 while i < n:
86 c = pat[i]
87 i = i+1
88 if c == '*':
89 res = res + '.*'
90 elif c == '?':
91 res = res + '.'
92 elif c == '[':
93 j = i
94 if j < n and pat[j] == '!':
95 j = j+1
96 if j < n and pat[j] == ']':
97 j = j+1
98 while j < n and pat[j] != ']':
99 j = j+1
100 if j >= n:
101 res = res + '\\['
102 else:
Fred Drake46d9fda2001-03-21 18:05:48 +0000103 stuff = pat[i:j].replace('\\','\\\\')
Tim Peters88869f92001-01-14 23:36:06 +0000104 i = j+1
105 if stuff[0] == '!':
Fred Drake46d9fda2001-03-21 18:05:48 +0000106 stuff = '^' + stuff[1:]
107 elif stuff[0] == '^':
108 stuff = '\\' + stuff
109 res = '%s[%s]' % (res, stuff)
Tim Peters88869f92001-01-14 23:36:06 +0000110 else:
111 res = res + re.escape(c)
Gregory P. Smith56629242009-11-01 20:33:31 +0000112 return res + '\Z(?ms)'