# fnmatch

**Module Overview**

The `fnmatch` module allows you to match file names using wildcard patterns, similar to the wildcards you might use in a command shell like Bash.

**Special Characters**

Here's how the special characters work:

* **?** - Matches any single character.
* **\*** - Matches any sequence of characters, including empty.
* **\[]** - Encloses a set of characters. Matches any character within the brackets.
* **\[!...]** - Encloses a set of characters. Matches any character not within the brackets.
* **.** - By default, does not match a dot (period).

**Real-World Example**

Let's say you have a directory with files named:

```
file1.txt
file2.txt
file3.txt
```

You could use `fnmatch` to find all files ending with `.txt`:

```python
import fnmatch

files = ['file1.txt', 'file2.txt', 'file3.txt']
result = fnmatch.filter(files, '*.txt')
print(result)  # Output: ['file1.txt', 'file2.txt', 'file3.txt']
```

**Potential Applications**

`fnmatch` is commonly used for:

* Filtering files based on file name patterns in directory listings.
* Autocompleting file names in text editors or command shells.
* Checking file names for specific formats or patterns (e.g., for validation).

***

### Glob-Style Wildcards

Glob-style wildcards are special characters used to match files and directories based on specific patterns. Here's a simplified explanation of each:

#### \* (asterisk)

* **Meaning:** Matches everything.
* **Example:** `"*.txt"` matches all files ending in ".txt", regardless of their name.

#### ? (question mark)

* **Meaning:** Matches any single character.
* **Example:** `"col?r"` matches "color", "colour", "co1or", etc.

#### \[seq] (square brackets)

* **Meaning:** Matches any character within the specified sequence.
* **Example:** `"f[aei]sh"` matches "fish", "fesh", and "fash".

#### \[!seq] (square brackets with exclamation)

* **Meaning:** Matches any character not within the specified sequence.
* **Example:** `"[!aeiou]n"` matches "kn", "gn", "wn", etc.

#### - (minus)

* **Meaning:** When used within square brackets, matches any character in the range specified before it.
* **Example:** `"d[a-z-]"` matches any single-letter lowercase directory name, including names with hyphens.

### Real-World Applications

Glob-style wildcards are commonly used in:

* **File Searching:** To find files meeting specific criteria.
* **Directory Creation:** To create directories based on patterns.
* **Data Filtering:** To select specific data from lists or databases.

### Code Implementation Examples

```python
import fnmatch

# File Searching
files = fnmatch.filter(os.listdir('/tmp'), '*.log')

# Directory Creation
os.mkdir('/var/log/app', mode=0o755)
os.mkdir('/var/log/web', mode=0o755)

# Data Filtering
data = ['apple', 'banana', 'cherry', 'dog', 'fish', 'grape']
fruits = fnmatch.filter(data, '*[aeiou]*')
print(fruits)  # ['apple', 'banana', 'cherry', 'grape']
```

***

**Literal Meta-characters**

* **Meaning:** These characters match themselves exactly.
* **Syntax:** Wrap them in brackets.
* **Example:** `'?'` matches the character `'?'`.

**Non-Special Filename Separator**

* **Meaning:** The filename separator (e.g., `/` in Unix) is not special in fnmatch.
* **Implication:** Pass the entire filename path to fnmatch, and it will apply the patterns to individual filename segments.

**Matching Hidden Files**

* **Meaning:** Filenames starting with a period (e.g., `.hidden`) are not treated specially.
* **Note:** They will match patterns like `'*'` and `'?'`.

**Cached Compiled Regex Patterns**

* **Meaning:** The `fnmatch`, `fnmatchcase`, and `filter` functions use a cache to store compiled regex patterns.
* **Benefit:** It improves performance by preventing duplicate compilation of the same patterns.

**Real-World Applications**

* **File Filtering:** Filtering files based on matching patterns.
* **Path Manipulation:** Matching specific path segments in complex file paths.
* **Config File Parsing:** Identifying configuration parameters based on matching patterns.

**Improved Code Example**

```python
import fnmatch

# Filter files with the pattern '*.py'
for file in os.listdir("./"):
    if fnmatch.fnmatch(file, "*.py"):
        print(file)

# Check if a file 'config.json' matches the pattern 'config*'
fnmatch.fnmatch("config.json", "config*")

# Filter files that start with 'hidden'
for file in os.listdir("./"):
    if fnmatch.fnmatch(file, "hidden*"):
        print(file)
```

***

**1. Understanding fnmatch()**

**Simplified Explanation:**

fnmatch() is a function that checks if a file name matches a specific pattern. It's like a secret code that you can use to find files that follow a certain rule.

**For example:**

If you want to find all files that end with the extension ".txt", you can use the pattern "\*.txt".

**2. Using fnmatch()**

**Code Snippet:**

```python
import fnmatch

# Get a list of files in the current directory
files = os.listdir('.')

# Find all files that match the "*.txt" pattern
txt_files = []
for file in files:
    if fnmatch.fnmatch(file, "*.txt"):
        txt_files.append(file)

# Print the list of ".txt" files
print(txt_files)
```

**Explanation:**

This code first lists all files in the current directory. Then, it iterates through each file and checks if it matches the "\*.txt" pattern. If a file matches, it's added to the "txt\_files" list. Finally, the "txt\_files" list is printed.

**Real-World Applications:**

* Searching for specific file types in a large directory
* Filtering files based on patterns in file management systems
* Automating tasks that involve finding files that meet certain criteria

**3. fnmatchcase()**

**Simplified Explanation:**

fnmatch() normally ignores the case of file names when matching patterns. For example, "text.txt" and "TEXT.TXT" would both match the "\*.txt" pattern.

**fnmatchcase()** is a special version of fnmatch() that considers the case of file names. If you use fnmatchcase() with the "\*.txt" pattern, only files with the exact name "text.txt" would match.

**Code Snippet:**

```python
import fnmatch

# Get a list of files in the current directory
files = os.listdir('.')

# Find all files that match the "*.txt" pattern, case-sensitively
txt_files = []
for file in files:
    if fnmatchcase(file, "*.txt"):
        txt_files.append(file)

# Print the list of ".txt" files
print(txt_files)
```

**Real-World Applications:**

* Finding files with specific case-sensitive names
* Ensuring that files are named consistently and accurately

***

### `fnmatchcase` Function in `fnmatch` Module

The `fnmatchcase` function in Python's `fnmatch` module performs case-sensitive pattern matching on filenames. It returns `True` if the given `name` matches the `pat` pattern, and `False` otherwise.

**Parameters:**

* **name**: A string representing the filename to be matched.
* **pat**: A string representing the pattern to be matched against. The pattern can contain wildcards like `*` (matches any number of characters) and `?` (matches a single character).

**Return Value:**

* **bool**: Returns `True` if the `name` matches the `pat` pattern, `False` otherwise.

**Example:**

```python
import fnmatch

name = 'myfile.txt'
pat = '*.txt'

result = fnmatchcase(name, pat)
print(result)  # Output: True
```

**Real-World Applications:**

* Filtering files based on their names. For example, you could use `fnmatchcase` to find all files with a specific extension or name.
* Matching filenames against user-defined patterns. For instance, you could use `fnmatchcase` to check if a file matches a set of criteria defined by the user.

**Improved Code Snippet:**

```python
import fnmatch

def find_files(directory, pattern):
    """
    Finds all files in the given directory that match the specified pattern.

    Args:
        directory: The directory to search.
        pattern: The pattern to match against.

    Returns:
        A list of matching files.
    """

    # Iterate over all files in the directory.
    for filename in os.listdir(directory):

        # Check if the filename matches the pattern.
        if fnmatchcase(filename, pattern):

            # If it does, add it to the list of matching files.
            matching_files.append(filename)

    # Return the list of matching files.
    return matching_files
```

This code snippet shows how to use `fnmatchcase` to find all files in a given directory that match a specific pattern.

***

**Simplified Explanation:**

The `fnmatch.filter()` function takes two inputs: a list of names and a pattern. It returns a new list containing only the names that match the pattern.

**Detailed Explanation:**

**Input Parameters:**

* `names`: A list of strings (file names or other names).
* `pat`: A pattern (a string containing wildcards) to match the names against.

**Matching Patterns:**

The pattern `pat` can contain the following wildcard characters:

* `*`: Matches any number of characters.
* `?`: Matches any single character.
* `[...]`: Matches any character within the square brackets.

**Implementation:**

The `fnmatch.filter()` function is implemented more efficiently than the following Python list comprehension:

```python
[n for n in names if fnmatch(n, pat)]
```

**Real-World Application:**

The `fnmatch.filter()` function can be used in various real-world scenarios:

* **File searching:** To search for files with specific names or patterns, such as finding all ".txt" files in a directory.
* **Data filtering:** To extract data from a list or array that matches certain criteria, such as filtering a list of email addresses to only include those from a specific domain.
* **Text processing:** To identify and manipulate text that conforms to a particular pattern, such as extracting phone numbers or URLs from a document.

**Improved Code Examples:**

Here's a complete code implementation of how to use `fnmatch.filter()` to find all ".txt" files in a directory:

```python
import fnmatch
import os

# Get the current working directory
cwd = os.getcwd()

# Create a list of all files in the directory
files = os.listdir(cwd)

# Use fnmatch.filter() to find all ".txt" files
txt_files = fnmatch.filter(files, "*.txt")

# Print the list of ".txt" files
print(txt_files)
```

***

**Function translate(pat)**

**Purpose:**

Converts a shell-style file pattern (*pat*) into a regular expression that can be used with the `re.match` function for pattern matching.

**How it works:**

Imagine you have a file pattern like `*.txt`. This pattern means "match any file that ends with `.txt`." However, to use this pattern in a Python program, we need to convert it into a regular expression. The `translate` function does this conversion for us.

**Example:**

```python
import fnmatch
import re

# Convert the file pattern "*.txt" into a regular expression
regex = fnmatch.translate("*.txt")

# Compile the regular expression into a match object
regex_object = re.compile(regex)

# Use the match object to match against a file name
match = regex_object.match("foobar.txt")

# Check if the match was successful
if match:
    print("Matched the file name")
```

**Improved Example:**

```python
import fnmatch
import re

# Define a function to check if a file name matches a pattern
def check_file_match(file_name, pattern):
    # Convert the pattern to a regular expression
    regex = fnmatch.translate(pattern)

    # Create a match object
    regex_object = re.compile(regex)

    # Match the file name against the pattern
    match = regex_object.match(file_name)

    # Return the result of the match
    return bool(match)

# Test the function with different file names and patterns
print(check_file_match("foobar.txt", "*.txt"))  # True
print(check_file_match("foobar.cpp", "*.txt"))  # False
```

**Potential Applications:**

* **File searching:** Find files with specific names or extensions within a directory.
* **Filename validation:** Check if a user-provided file name matches a specific format.
* **Pattern matching:** Identify text strings that match a predefined set of characters.
