github.com/grumpyhome/grumpy@v0.3.1-0.20201208125205-7b775405bdf1/grumpy-runtime-src/third_party/stdlib/fnmatch.py (about) 1 """Filename matching with shell patterns. 2 3 fnmatch(FILENAME, PATTERN) matches according to the local convention. 4 fnmatchcase(FILENAME, PATTERN) always takes case in account. 5 6 The functions operate by translating the pattern into a regular 7 expression. They cache the compiled regular expressions for speed. 8 9 The function translate(PATTERN) returns a regular expression 10 corresponding to PATTERN. (It does not compile it.) 11 """ 12 13 import re 14 15 __all__ = ["filter", "fnmatch", "fnmatchcase", "translate"] 16 17 _cache = {} 18 _MAXCACHE = 100 19 20 def _purge(): 21 """Clear the pattern cache""" 22 # _cache.clear() 23 globals()['_cache'] = {} 24 25 def fnmatch(name, pat): 26 """Test whether FILENAME matches PATTERN. 27 28 Patterns are Unix shell style: 29 30 * matches everything 31 ? matches any single character 32 [seq] matches any character in seq 33 [!seq] matches any char not in seq 34 35 An initial period in FILENAME is not special. 36 Both FILENAME and PATTERN are first case-normalized 37 if the operating system requires it. 38 If you don't want this, use fnmatchcase(FILENAME, PATTERN). 39 """ 40 41 # import os 42 # name = os.path.normcase(name) 43 # pat = os.path.normcase(pat) 44 return fnmatchcase(name, pat) 45 46 def filter(names, pat): 47 """Return the subset of the list NAMES that match PAT""" 48 import os 49 # import posixpath 50 result=[] 51 # pat=os.path.normcase(pat) 52 try: 53 re_pat = _cache[pat] 54 except KeyError: 55 res = translate(pat) 56 if len(_cache) >= _MAXCACHE: 57 # _cache.clear() 58 globals()['_cache'] = {} 59 _cache[pat] = re_pat = re.compile(res) 60 match = re_pat.match 61 # if os.path is posixpath: 62 if 1: 63 # normcase on posix is NOP. Optimize it away from the loop. 64 for name in names: 65 if match(name): 66 result.append(name) 67 else: 68 for name in names: 69 if match(os.path.normcase(name)): 70 result.append(name) 71 return result 72 73 def fnmatchcase(name, pat): 74 """Test whether FILENAME matches PATTERN, including case. 75 76 This is a version of fnmatch() which doesn't case-normalize 77 its arguments. 78 """ 79 80 try: 81 re_pat = _cache[pat] 82 except KeyError: 83 res = translate(pat) 84 if len(_cache) >= _MAXCACHE: 85 # _cache.clear() 86 globals()['_cache'] = {} 87 _cache[pat] = re_pat = re.compile(res) 88 return re_pat.match(name) is not None 89 90 def translate(pat): 91 """Translate a shell PATTERN to a regular expression. 92 93 There is no way to quote meta-characters. 94 """ 95 96 i, n = 0, len(pat) 97 res = '' 98 while i < n: 99 c = pat[i] 100 i = i+1 101 if c == '*': 102 res = res + '.*' 103 elif c == '?': 104 res = res + '.' 105 elif c == '[': 106 j = i 107 if j < n and pat[j] == '!': 108 j = j+1 109 if j < n and pat[j] == ']': 110 j = j+1 111 while j < n and pat[j] != ']': 112 j = j+1 113 if j >= n: 114 res = res + '\\[' 115 else: 116 stuff = pat[i:j].replace('\\','\\\\') 117 i = j+1 118 if stuff[0] == '!': 119 stuff = '^' + stuff[1:] 120 elif stuff[0] == '^': 121 stuff = '\\' + stuff 122 res = '%s[%s]' % (res, stuff) 123 else: 124 res = res + re.escape(c) 125 return res + '\Z(?ms)'