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)'