import re


def _event_id_func(desc, event_id, trig_shift_by_type, dropped_desc):
    """Get integers from string description.

    This function can be passed as event_id to events_from_annotations
    function.

    Parameters
    ----------
    desc : str
        The description of the event.
    event_id : dict
        The default mapping from desc to integer.
    trig_shift_by_type: dict | None
        The names of marker types to which an offset should be added.
        If dict, the keys specify marker types (case is ignored), so that the
        corresponding value (an integer) will be added to the trigger value of
        all events of this type. If the value for a key is in the dict is None,
        all markers of this type will be ignored. If None (default), no offset
        is added, which may lead to different marker types being mapped to the
        same event id.
    dropped_desc : list
        Used to log the dropped descriptions.

    Returns
    -------
    trigger : int | None
        The integer corresponding to the specific event. If None,
        then a proper integer cannot be found and the event is typically
        ignored.
    """
    mtype, mdesc = desc.split('/')
    found = False
    if (mdesc in event_id) or (mtype == "New Segment"):
        trigger = event_id.get(mdesc, None)
        found = True
    else:
        try:
            # Match any three digit marker value (padded with whitespace).
            # In BrainVision Recorder, the markers sometimes have a prefix
            # depending on the type, e.g., Stimulus=S, Response=R,
            # Optical=O, ... Note that any arbitrary stimulus type can be
            # defined. So we match any single character that is not
            # forbidden by BrainVision Recorder: [^a-z$%\-@/\\|;,:.\s]
            marker_regexp = r'^[^a-z$%\-@/\\|;,:.\s]{0,1}([\s\d]{2}\d{1})$'
            trigger = int(re.findall(marker_regexp, mdesc)[0])
        except IndexError:
            trigger = None

    if mtype.lower() in trig_shift_by_type:
        cur_shift = trig_shift_by_type[mtype.lower()]
        if cur_shift is not None:
            trigger += cur_shift
        else:
            # The trigger has been deliberately shifted to None. Do not
            # add this to "dropped" so we do not warn about something
            # that was done deliberately. Just continue with next item.
            trigger = None
            found = True

    if trigger is None and not found:
        dropped_desc.append(desc)

    return trigger