Merged revisions 81181 via svnmerge from
[python/dscho.git] / Lib / fnmatch.py
blob30c0a922f229464317b3f6726597d5fe252cf380
1 """Filename matching with shell patterns.
3 fnmatch(FILENAME, PATTERN) matches according to the local convention.
4 fnmatchcase(FILENAME, PATTERN) always takes case in account.
6 The functions operate by translating the pattern into a regular
7 expression. They cache the compiled regular expressions for speed.
9 The function translate(PATTERN) returns a regular expression
10 corresponding to PATTERN. (It does not compile it.)
11 """
13 import re
15 __all__ = ["filter", "fnmatch","fnmatchcase","translate"]
17 _cache = {} # Maps text patterns to compiled regexen.
18 _cacheb = {} # Ditto for bytes patterns.
20 def fnmatch(name, pat):
21 """Test whether FILENAME matches PATTERN.
23 Patterns are Unix shell style:
25 * matches everything
26 ? matches any single character
27 [seq] matches any character in seq
28 [!seq] matches any char not in seq
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 """
36 import os
37 name = os.path.normcase(name)
38 pat = os.path.normcase(pat)
39 return fnmatchcase(name, pat)
41 def _compile_pattern(pat):
42 cache = _cacheb if isinstance(pat, bytes) else _cache
43 regex = cache.get(pat)
44 if regex is None:
45 if isinstance(pat, bytes):
46 pat_str = str(pat, 'ISO-8859-1')
47 res_str = translate(pat_str)
48 res = bytes(res_str, 'ISO-8859-1')
49 else:
50 res = translate(pat)
51 cache[pat] = regex = re.compile(res)
52 return regex.match
54 def filter(names, pat):
55 """Return the subset of the list NAMES that match PAT"""
56 import os,posixpath
57 result = []
58 pat = os.path.normcase(pat)
59 match = _compile_pattern(pat)
60 if os.path is posixpath:
61 # normcase on posix is NOP. Optimize it away from the loop.
62 for name in names:
63 if match(name):
64 result.append(name)
65 else:
66 for name in names:
67 if match(os.path.normcase(name)):
68 result.append(name)
69 return result
71 def fnmatchcase(name, pat):
72 """Test whether FILENAME matches PATTERN, including case.
74 This is a version of fnmatch() which doesn't case-normalize
75 its arguments.
76 """
78 match = _compile_pattern(pat)
79 return match(name) is not None
81 def translate(pat):
82 """Translate a shell PATTERN to a regular expression.
84 There is no way to quote meta-characters.
85 """
87 i, n = 0, len(pat)
88 res = ''
89 while i < n:
90 c = pat[i]
91 i = i+1
92 if c == '*':
93 res = res + '.*'
94 elif c == '?':
95 res = res + '.'
96 elif c == '[':
97 j = i
98 if j < n and pat[j] == '!':
99 j = j+1
100 if j < n and pat[j] == ']':
101 j = j+1
102 while j < n and pat[j] != ']':
103 j = j+1
104 if j >= n:
105 res = res + '\\['
106 else:
107 stuff = pat[i:j].replace('\\','\\\\')
108 i = j+1
109 if stuff[0] == '!':
110 stuff = '^' + stuff[1:]
111 elif stuff[0] == '^':
112 stuff = '\\' + stuff
113 res = '%s[%s]' % (res, stuff)
114 else:
115 res = res + re.escape(c)
116 return res + '\Z(?ms)'