SoFunction
Updated on 2024-11-17

Details on the use of the fnmatch module in Python

fnamtch is filenamematch, a linux shell-style matching module in python for filename matching and filtering.

The fnmatch() function's matching capabilities fall somewhere between simple string methods and powerful regular expressions, which is usually a more reasonable solution when a simple wildcard is all that is needed in a data processing operation. The main purpose of this module is to match file names, and the matching pattern is Unix shell style. The source code is simple:

"""Filename matching with shell patterns.

fnmatch(FILENAME, PATTERN) matches according to the local convention.
fnmatchcase(FILENAME, PATTERN) always takes case in account.

The functions operate by translating the pattern into a regular
expression. They cache the compiled regular expressions for speed.

The function translate(PATTERN) returns a regular expression
corresponding to PATTERN. (It does not compile it.)
"""
import os
import posixpath
import re
import functools

__all__ = ["filter", "fnmatch", "fnmatchcase", "translate"]

def fnmatch(name, pat):
  """Test whether FILENAME matches PATTERN.

  Patterns are Unix shell style:

  *    matches everything
  ?    matches any single character
  [seq]  matches any character in seq
  [!seq] matches any char not in seq

  An initial period in FILENAME is not special.
  Both FILENAME and PATTERN are first case-normalized
  if the operating system requires it.
  If you don't want this, use fnmatchcase(FILENAME, PATTERN).
  """
  name = (name)
  pat = (pat)
  return fnmatchcase(name, pat)

@functools.lru_cache(maxsize=256, typed=True)
def _compile_pattern(pat):
  if isinstance(pat, bytes):
    pat_str = str(pat, 'ISO-8859-1')
    res_str = translate(pat_str)
    res = bytes(res_str, 'ISO-8859-1')
  else:
    res = translate(pat)
  return (res).match

def filter(names, pat):
  """Return the subset of the list NAMES that match PAT."""
  result = []
  pat = (pat)
  match = _compile_pattern(pat)
  if  is posixpath:
    # normcase on posix is NOP. Optimize it away from the loop.
    for name in names:
      if match(name):
        (name)
  else:
    for name in names:
      if match((name)):
        (name)
  return result

def fnmatchcase(name, pat):
  """Test whether FILENAME matches PATTERN, including case.

  This is a version of fnmatch() which doesn't case-normalize
  its arguments.
  """
  match = _compile_pattern(pat)
  return match(name) is not None


def translate(pat):
  """Translate a shell PATTERN to a regular expression.

  There is no way to quote meta-characters.
  """

  i, n = 0, len(pat)
  res = ''
  while i < n:
    c = pat[i]
    i = i+1
    if c == '*':
      res = res + '.*'
    elif c == '?':
      res = res + '.'
    elif c == '[':
      j = i
      if j < n and pat[j] == '!':
        j = j+1
      if j < n and pat[j] == ']':
        j = j+1
      while j < n and pat[j] != ']':
        j = j+1
      if j >= n:
        res = res + '\\['
      else:
        stuff = pat[i:j].replace('\\','\\\\')
        i = j+1
        if stuff[0] == '!':
          stuff = '^' + stuff[1:]
        elif stuff[0] == '^':
          stuff = '\\' + stuff
        res = '%s[%s]' % (res, stuff)
    else:
      res = res + (c)
  return r'(?s:%s)\Z' % res

5 functions in fnmatch ["filter", "fnmatch", "fnmatchcase", "translate"].

filter Returns results in the form of a list

def gen_find(filepat, top):
  """
  Finds all filenames in the directory tree that match the shell's regular match
  :param filepat: shell regular
  :param top: Directory path
  :return: file absolute path generator
  """
  for path, _, filenames in (top):
    for file in (filenames, filepat):
      yield (path, file)

fnmatch

# List all python files in the tuple
pyfiles = [py for py in ('', '', '') if fnmatch(py, '*.py')]
# string startswith() cap (a poem) endswith() method is also useful for filtering the contents of a directory

fnmatchcase Case-sensitive file matching

# A feature of these two functions that is often overlooked is that they are also useful when working with strings that are not filenames. For example, suppose you have a list of street addresses as data
address = [
  '5412 N CLARK ST',
  '1060 W ADDISON ST',
  '1039 W GRANVILLE AVE',
  '2122 N CLARK ST',
  '4802 N BROADWAY',
]
print([addr for addr in address if fnmatchcase(addr, '* ST')])

As mentioned earlier, fnmatch is a Unix shell matching style that can be converted to a regular expression using translate, as an example.

shell_match = 'Celery_?*.py'
print(translate(shell_match))
# output result:(?s:Celery_..*\.py)\Z

Celery_... *\.py is how regular expressions are written.

This is the whole content of this article.