def bioul_tags_to_spans(tag_sequence: List[str],
                        classes_to_ignore: List[str] = None) -> List[TypedStringSpan]:
    """
    Given a sequence corresponding to BIOUL tags, extracts spans.
    Spans are inclusive and can be of zero length, representing a single word span.
    Ill-formed spans are not allowed and will raise ``InvalidTagSequence``.
    This function works properly when the spans are unlabeled (i.e., your labels are
    simply "B", "I", "O", "U", and "L").

    Parameters
    ----------
    tag_sequence : ``List[str]``, required.
        The tag sequence encoded in BIOUL, e.g. ["B-PER", "L-PER", "O"].
    classes_to_ignore : ``List[str]``, optional (default = None).
        A list of string class labels `excluding` the bio tag
        which should be ignored when extracting spans.

    Returns
    -------
    spans : ``List[TypedStringSpan]``
        The typed, extracted spans from the sequence, in the format (label, (span_start, span_end)).
    """
    spans = []
    classes_to_ignore = classes_to_ignore or []
    index = 0
    while index < len(tag_sequence):
        label = tag_sequence[index]
        if label[0] == 'U':
            spans.append((label.partition('-')[2], (index, index)))
        elif label[0] == 'B':
            start = index
            while label[0] != 'L':
                index += 1
                if index >= len(tag_sequence):
                    raise InvalidTagSequence(tag_sequence)
                label = tag_sequence[index]
                if not (label[0] == 'I' or label[0] == 'L'):
                    raise InvalidTagSequence(tag_sequence)
            spans.append((label.partition('-')[2], (start, index)))
        else:
            if label != 'O':
                raise InvalidTagSequence(tag_sequence)
        index += 1
    return [span for span in spans if span[0] not in classes_to_ignore]