blob: 99002e6e6bc20cf12df1f531e057dfa716b0e4f3 [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
R. David Murray2ab02f02010-07-10 14:06:51 +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 Murrayabd45532010-07-09 13:16:00 +000018_MAXCACHE = 100
Guido van Rossum762c39e1991-01-01 18:11:14 +000019
R. David Murray2ab02f02010-07-10 14:06:51 +000020def _purge():
21 """Clear the pattern cache"""
22 _cache.clear()
23
Guido van Rossum762c39e1991-01-01 18:11:14 +000024def fnmatch(name, pat):
Tim Peters88869f92001-01-14 23:36:06 +000025 """Test whether FILENAME matches PATTERN.
26
27 Patterns are Unix shell style:
28
29 * matches everything
30 ? matches any single character
31 [seq] matches any character in seq
32 [!seq] matches any char not in seq
33
34 An initial period in FILENAME is not special.
35 Both FILENAME and PATTERN are first case-normalized
36 if the operating system requires it.
37 If you don't want this, use fnmatchcase(FILENAME, PATTERN).
38 """
39
40 import os
41 name = os.path.normcase(name)
42 pat = os.path.normcase(pat)
43 return fnmatchcase(name, pat)
Guido van Rossum7e4b2de1995-01-27 02:41:45 +000044
Martin v. Löwisb5d4d2a2001-06-06 06:24:38 +000045def filter(names, pat):
46 """Return the subset of the list NAMES that match PAT"""
47 import os,posixpath
48 result=[]
49 pat=os.path.normcase(pat)
Serhiy Storchaka3ce465a2015-01-27 11:40:51 +020050 try:
51 re_pat = _cache[pat]
52 except KeyError:
Martin v. Löwisb5d4d2a2001-06-06 06:24:38 +000053 res = translate(pat)
R. David Murrayabd45532010-07-09 13:16:00 +000054 if len(_cache) >= _MAXCACHE:
55 _cache.clear()
Serhiy Storchaka3ce465a2015-01-27 11:40:51 +020056 _cache[pat] = re_pat = re.compile(res)
57 match = re_pat.match
Martin v. Löwisb5d4d2a2001-06-06 06:24:38 +000058 if os.path is posixpath:
59 # normcase on posix is NOP. Optimize it away from the loop.
60 for name in names:
61 if match(name):
62 result.append(name)
63 else:
64 for name in names:
65 if match(os.path.normcase(name)):
66 result.append(name)
67 return result
68
Guido van Rossum7e4b2de1995-01-27 02:41:45 +000069def fnmatchcase(name, pat):
Tim Peters88869f92001-01-14 23:36:06 +000070 """Test whether FILENAME matches PATTERN, including case.
71
72 This is a version of fnmatch() which doesn't case-normalize
73 its arguments.
74 """
75
Serhiy Storchaka3ce465a2015-01-27 11:40:51 +020076 try:
77 re_pat = _cache[pat]
78 except KeyError:
Tim Peters88869f92001-01-14 23:36:06 +000079 res = translate(pat)
R. David Murrayabd45532010-07-09 13:16:00 +000080 if len(_cache) >= _MAXCACHE:
81 _cache.clear()
Serhiy Storchaka3ce465a2015-01-27 11:40:51 +020082 _cache[pat] = re_pat = re.compile(res)
83 return re_pat.match(name) is not None
Guido van Rossum762c39e1991-01-01 18:11:14 +000084
Guido van Rossum05e52191992-01-12 23:29:29 +000085def translate(pat):
Tim Peters88869f92001-01-14 23:36:06 +000086 """Translate a shell PATTERN to a regular expression.
87
88 There is no way to quote meta-characters.
89 """
90
91 i, n = 0, len(pat)
92 res = ''
93 while i < n:
94 c = pat[i]
95 i = i+1
96 if c == '*':
97 res = res + '.*'
98 elif c == '?':
99 res = res + '.'
100 elif c == '[':
101 j = i
102 if j < n and pat[j] == '!':
103 j = j+1
104 if j < n and pat[j] == ']':
105 j = j+1
106 while j < n and pat[j] != ']':
107 j = j+1
108 if j >= n:
109 res = res + '\\['
110 else:
Fred Drake46d9fda2001-03-21 18:05:48 +0000111 stuff = pat[i:j].replace('\\','\\\\')
Tim Peters88869f92001-01-14 23:36:06 +0000112 i = j+1
113 if stuff[0] == '!':
Fred Drake46d9fda2001-03-21 18:05:48 +0000114 stuff = '^' + stuff[1:]
115 elif stuff[0] == '^':
116 stuff = '\\' + stuff
117 res = '%s[%s]' % (res, stuff)
Tim Peters88869f92001-01-14 23:36:06 +0000118 else:
119 res = res + re.escape(c)
Gregory P. Smithb98d6b22009-08-16 18:52:58 +0000120 return res + '\Z(?ms)'