blob: 7c20e74abeecbec0a4f24fcdd2a8473bbb39a3d9 [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"""
Brett Cannoncc143202010-07-23 16:22:25 +000012import os
13import posixpath
Guido van Rossum9694fca1997-10-22 21:00:49 +000014import re
15
Antoine Pitrouf14c2632010-08-09 12:47:33 +000016__all__ = ["filter", "fnmatch", "fnmatchcase", "purge", "translate"]
17
18_cache = {} # Maps text patterns to compiled regexen.
19_cacheb = {} # Ditto for bytes patterns.
20_MAXCACHE = 100 # Maximum size of caches.
21
22
23def purge():
24 """Clear the pattern cache."""
25 _cache.clear()
26 _cacheb.clear()
27
Brett Cannoncc143202010-07-23 16:22:25 +000028
Guido van Rossum762c39e1991-01-01 18:11:14 +000029def fnmatch(name, pat):
Tim Peters88869f92001-01-14 23:36:06 +000030 """Test whether FILENAME matches PATTERN.
31
32 Patterns are Unix shell style:
33
34 * matches everything
35 ? matches any single character
36 [seq] matches any character in seq
37 [!seq] matches any char not in seq
38
39 An initial period in FILENAME is not special.
40 Both FILENAME and PATTERN are first case-normalized
41 if the operating system requires it.
42 If you don't want this, use fnmatchcase(FILENAME, PATTERN).
43 """
Tim Peters88869f92001-01-14 23:36:06 +000044 name = os.path.normcase(name)
45 pat = os.path.normcase(pat)
46 return fnmatchcase(name, pat)
Guido van Rossum7e4b2de1995-01-27 02:41:45 +000047
Antoine Pitrouf14c2632010-08-09 12:47:33 +000048
49def _compile_pattern(pat):
50 cache = _cacheb if isinstance(pat, bytes) else _cache
51 regex = cache.get(pat)
52 if regex is None:
53 if isinstance(pat, bytes):
54 pat_str = str(pat, 'ISO-8859-1')
55 res_str = translate(pat_str)
56 res = bytes(res_str, 'ISO-8859-1')
57 else:
58 res = translate(pat)
59 if len(cache) >= _MAXCACHE:
60 cache.clear()
61 cache[pat] = regex = re.compile(res)
62 return regex.match
63
Brett Cannoncc143202010-07-23 16:22:25 +000064
Martin v. Löwisb5d4d2a2001-06-06 06:24:38 +000065def filter(names, pat):
Brett Cannoncc143202010-07-23 16:22:25 +000066 """Return the subset of the list NAMES that match PAT."""
Guido van Rossumf0af3e32008-10-02 18:55:37 +000067 result = []
68 pat = os.path.normcase(pat)
Antoine Pitrouf14c2632010-08-09 12:47:33 +000069 match = _compile_pattern(pat)
Martin v. Löwisb5d4d2a2001-06-06 06:24:38 +000070 if os.path is posixpath:
71 # normcase on posix is NOP. Optimize it away from the loop.
72 for name in names:
73 if match(name):
74 result.append(name)
75 else:
76 for name in names:
77 if match(os.path.normcase(name)):
78 result.append(name)
79 return result
80
Antoine Pitrouf14c2632010-08-09 12:47:33 +000081
Guido van Rossum7e4b2de1995-01-27 02:41:45 +000082def fnmatchcase(name, pat):
Tim Peters88869f92001-01-14 23:36:06 +000083 """Test whether FILENAME matches PATTERN, including case.
84
85 This is a version of fnmatch() which doesn't case-normalize
86 its arguments.
87 """
Antoine Pitrouf14c2632010-08-09 12:47:33 +000088 match = _compile_pattern(pat)
Guido van Rossumf0af3e32008-10-02 18:55:37 +000089 return match(name) is not None
Guido van Rossum762c39e1991-01-01 18:11:14 +000090
Brett Cannoncc143202010-07-23 16:22:25 +000091
Guido van Rossum05e52191992-01-12 23:29:29 +000092def translate(pat):
Tim Peters88869f92001-01-14 23:36:06 +000093 """Translate a shell PATTERN to a regular expression.
94
95 There is no way to quote meta-characters.
96 """
97
98 i, n = 0, len(pat)
99 res = ''
100 while i < n:
101 c = pat[i]
102 i = i+1
103 if c == '*':
104 res = res + '.*'
105 elif c == '?':
106 res = res + '.'
107 elif c == '[':
108 j = i
109 if j < n and pat[j] == '!':
110 j = j+1
111 if j < n and pat[j] == ']':
112 j = j+1
113 while j < n and pat[j] != ']':
114 j = j+1
115 if j >= n:
116 res = res + '\\['
117 else:
Fred Drake46d9fda2001-03-21 18:05:48 +0000118 stuff = pat[i:j].replace('\\','\\\\')
Tim Peters88869f92001-01-14 23:36:06 +0000119 i = j+1
120 if stuff[0] == '!':
Fred Drake46d9fda2001-03-21 18:05:48 +0000121 stuff = '^' + stuff[1:]
122 elif stuff[0] == '^':
123 stuff = '\\' + stuff
124 res = '%s[%s]' % (res, stuff)
Tim Peters88869f92001-01-14 23:36:06 +0000125 else:
126 res = res + re.escape(c)
Gregory P. Smith01099702009-08-16 18:58:46 +0000127 return res + '\Z(?ms)'