Find keys and values in a (nested) dictionary with regular expression pattern.
    Examples:
        >>> from collections import OrderedDict
        >>> d = OrderedDict((
        ...     ('foo', 'bar'),
        ...     ('bar', 'baz'),
        ...     ('nested', dict(p1=1, p2=2)),
        ...     ('lst', ['bar', 'foo', dict(p3=3, p4=4)])
        ... ))
        >>> f = dict_find_pattern(d, '.*a.*', search_in_keys=True, search_in_values=False)
        >>> def print_findings(f):
        ...     for _, key, value in f:
        ...         print(key, value)
        >>> print_findings(f)
        bar baz
        >>> f = dict_find_pattern(d, '.*a.*', search_in_keys=False, search_in_values=True)
        >>> print_findings(f)
        foo bar
        bar baz

    Args:
        _dict: Dictionary to scan for the specified pattern.
        pattern: The pattern to scan for.
        search_in_keys: If True keys will be probed for the pattern; otherwise not.
        search_in_values: If True values will be probed for the pattern; otherwise not.

    Returns:
        Generator to iterate over the findings.

def dict_find_pattern(_dict: Dict[Any, Any], pattern: str, search_in_keys: bool = True,
                      search_in_values: bool = True) -> PatternGenerator:
    """
    Find keys and values in a (nested) dictionary with regular expression pattern.
    Examples:
        >>> from collections import OrderedDict
        >>> d = OrderedDict((
        ...     ('foo', 'bar'),
        ...     ('bar', 'baz'),
        ...     ('nested', dict(p1=1, p2=2)),
        ...     ('lst', ['bar', 'foo', dict(p3=3, p4=4)])
        ... ))
        >>> f = dict_find_pattern(d, '.*a.*', search_in_keys=True, search_in_values=False)
        >>> def print_findings(f):
        ...     for _, key, value in f:
        ...         print(key, value)
        >>> print_findings(f)
        bar baz
        >>> f = dict_find_pattern(d, '.*a.*', search_in_keys=False, search_in_values=True)
        >>> print_findings(f)
        foo bar
        bar baz

    Args:
        _dict: Dictionary to scan for the specified pattern.
        pattern: The pattern to scan for.
        search_in_keys: If True keys will be probed for the pattern; otherwise not.
        search_in_values: If True values will be probed for the pattern; otherwise not.

    Returns:
        Generator to iterate over the findings.
    """

    def find(dic: Dict[Any, Any], regex: Pattern[str]) -> PatternGenerator:
        Validator.instance_of(target_type=dict, raise_ex=True, dic=dic)

        for k, val in dic.items():
            if search_in_keys and isinstance(k, str) and regex.match(k):
                yield dic, k, val
            if search_in_values and isinstance(val, str) and regex.match(val):
                yield dic, k, val
            if isinstance(val, list):
                for litem in val:
                    if isinstance(litem, dict):
                        for j in find(litem, regex):
                            yield j
            if isinstance(val, dict):
                for j in find(val, regex):
                    yield j

    regex = re.compile(pattern)
    return find(_dict, regex)