blob: be1fd1d16cea443d2264022f12feb9b6d115c75f [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 Murrayca126a02010-07-10 14:00:10 +000015__all__ = ["filter", "fnmatch", "fnmatchcase", "translate"]
Skip Montanaroeccd02a2001-01-20 23:34:12 +000016
Guido van Rossum3f2291f2008-10-03 16:38:30 +000017_cache = {} # Maps text patterns to compiled regexen.
18_cacheb = {} # Ditto for bytes patterns.
R. David Murrayead883a2010-07-09 13:16:26 +000019_MAXCACHE = 100 # Maximum size of caches
Guido van Rossum762c39e1991-01-01 18:11:14 +000020
R. David Murrayca126a02010-07-10 14:00:10 +000021def _purge():
22 """Clear the pattern cache"""
23 _cache.clear()
24 _cacheb.clear()
25
Guido van Rossum762c39e1991-01-01 18:11:14 +000026def fnmatch(name, pat):
Tim Peters88869f92001-01-14 23:36:06 +000027 """Test whether FILENAME matches PATTERN.
28
29 Patterns are Unix shell style:
30
31 * matches everything
32 ? matches any single character
33 [seq] matches any character in seq
34 [!seq] matches any char not in seq
35
36 An initial period in FILENAME is not special.
37 Both FILENAME and PATTERN are first case-normalized
38 if the operating system requires it.
39 If you don't want this, use fnmatchcase(FILENAME, PATTERN).
40 """
41
42 import os
43 name = os.path.normcase(name)
44 pat = os.path.normcase(pat)
45 return fnmatchcase(name, pat)
Guido van Rossum7e4b2de1995-01-27 02:41:45 +000046
Guido van Rossumf0af3e32008-10-02 18:55:37 +000047def _compile_pattern(pat):
Guido van Rossum3f2291f2008-10-03 16:38:30 +000048 cache = _cacheb if isinstance(pat, bytes) else _cache
49 regex = cache.get(pat)
Guido van Rossumf0af3e32008-10-02 18:55:37 +000050 if regex is None:
51 if isinstance(pat, bytes):
52 pat_str = str(pat, 'ISO-8859-1')
53 res_str = translate(pat_str)
54 res = bytes(res_str, 'ISO-8859-1')
55 else:
56 res = translate(pat)
R. David Murrayead883a2010-07-09 13:16:26 +000057 if len(cache) >= _MAXCACHE:
58 cache.clear()
Guido van Rossum3f2291f2008-10-03 16:38:30 +000059 cache[pat] = regex = re.compile(res)
Guido van Rossumf0af3e32008-10-02 18:55:37 +000060 return regex.match
61
Martin v. Löwisb5d4d2a2001-06-06 06:24:38 +000062def filter(names, pat):
63 """Return the subset of the list NAMES that match PAT"""
64 import os,posixpath
Guido van Rossumf0af3e32008-10-02 18:55:37 +000065 result = []
66 pat = os.path.normcase(pat)
67 match = _compile_pattern(pat)
Martin v. Löwisb5d4d2a2001-06-06 06:24:38 +000068 if os.path is posixpath:
69 # normcase on posix is NOP. Optimize it away from the loop.
70 for name in names:
71 if match(name):
72 result.append(name)
73 else:
74 for name in names:
75 if match(os.path.normcase(name)):
76 result.append(name)
77 return result
78
Guido van Rossum7e4b2de1995-01-27 02:41:45 +000079def fnmatchcase(name, pat):
Tim Peters88869f92001-01-14 23:36:06 +000080 """Test whether FILENAME matches PATTERN, including case.
81
82 This is a version of fnmatch() which doesn't case-normalize
83 its arguments.
84 """
85
Guido van Rossumf0af3e32008-10-02 18:55:37 +000086 match = _compile_pattern(pat)
87 return match(name) is not None
Guido van Rossum762c39e1991-01-01 18:11:14 +000088
Guido van Rossum05e52191992-01-12 23:29:29 +000089def translate(pat):
Tim Peters88869f92001-01-14 23:36:06 +000090 """Translate a shell PATTERN to a regular expression.
91
92 There is no way to quote meta-characters.
93 """
94
95 i, n = 0, len(pat)
96 res = ''
97 while i < n:
98 c = pat[i]
99 i = i+1
100 if c == '*':
101 res = res + '.*'
102 elif c == '?':
103 res = res + '.'
104 elif c == '[':
105 j = i
106 if j < n and pat[j] == '!':
107 j = j+1
108 if j < n and pat[j] == ']':
109 j = j+1
110 while j < n and pat[j] != ']':
111 j = j+1
112 if j >= n:
113 res = res + '\\['
114 else:
Fred Drake46d9fda2001-03-21 18:05:48 +0000115 stuff = pat[i:j].replace('\\','\\\\')
Tim Peters88869f92001-01-14 23:36:06 +0000116 i = j+1
117 if stuff[0] == '!':
Fred Drake46d9fda2001-03-21 18:05:48 +0000118 stuff = '^' + stuff[1:]
119 elif stuff[0] == '^':
120 stuff = '\\' + stuff
121 res = '%s[%s]' % (res, stuff)
Tim Peters88869f92001-01-14 23:36:06 +0000122 else:
123 res = res + re.escape(c)
Gregory P. Smith6c4a7252009-11-01 20:36:24 +0000124 return res + '\Z(?ms)'