import re


def assign_scanner(scanner, mappings, flavors, filename, source):
    """Assigns scanners based on mappings and file data.

    Performs the task of assigning scanners based on the scan configuration
    mappings and file flavors, filename, and source. Assignment supports
    positive and negative matching: scanners are assigned if any positive
    categories are matched and no negative categories are matched. Flavors are
    literal matches, filename and source matches uses regular expressions.

    Args:
        scanner: Name of the scanner being assigned.
        mappings: List of dictionaries that contain values used to assign
            the scanner to the file.
        flavors: List of file flavors to use during scanner assignment.
        filename: Filename to use during scanner assignment.
        source: File source to use during scanner assignment.

    Returns:
        A dictionary containing the assigned scanner or None.
    """
    for mapping in mappings:
        negatives = mapping.get("negative", {})
        positives = mapping.get("positive", {})
        neg_flavors = negatives.get("flavors", [])
        neg_filename = negatives.get("filename", None)
        neg_source = negatives.get("source", None)
        pos_flavors = positives.get("flavors", [])
        pos_filename = positives.get("filename", None)
        pos_source = positives.get("source", None)
        assigned_scanner = {"scanner_name": scanner,
                            "priority": mapping.get("priority", 5),
                            "options": mapping.get("options", {})}

        for neg_flavor in neg_flavors:
            if neg_flavor in flavors:
                return None
        if neg_filename is not None:
            if re.search(neg_filename, filename) is not None:
                return None
        if neg_source is not None:
            if re.search(neg_source, source) is not None:
                return None
        for pos_flavor in pos_flavors:
            if pos_flavor == "*" or pos_flavor in flavors:
                return assigned_scanner
        if pos_filename is not None:
            if re.search(pos_filename, filename) is not None:
                return assigned_scanner
        if pos_source is not None:
            if re.search(pos_source, source) is not None:
                return assigned_scanner
    return None