code: def bio_tags_to_spans(
      tag_sequence: List[str], classes_to_ignore: List[str] = None
  ) -> List[TypedStringSpan]:
      """
      Given a sequence corresponding to BIO tags, extracts spans.
      Spans are inclusive and can be of zero length, representing a single word span.
      Ill-formed spans are also included (i.e those which do not start with a "B-LABEL"),
      as otherwise it is possible to get a perfect precision score whilst still predicting
      ill-formed spans in addition to the correct spans. This function works properly when
      the spans are unlabeled (i.e., your labels are simply "B", "I", and "O").
  
      # Parameters
  
      tag_sequence : `List[str]`, required.
          The integer class labels for a sequence.
      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)).
          Note that the label `does not` contain any BIO tag prefixes.
      """
      classes_to_ignore = classes_to_ignore or []
      spans: Set[Tuple[str, Tuple[int, int]]] = set()
      span_start = 0
      span_end = 0
      active_conll_tag = None
      for index, string_tag in enumerate(tag_sequence):
          # Actual BIO tag.
          bio_tag = string_tag[0]
          if bio_tag not in ["B", "I", "O"]:
              raise InvalidTagSequence(tag_sequence)
          conll_tag = string_tag[2:]
          if bio_tag == "O" or conll_tag in classes_to_ignore:
              # The span has ended.
              if active_conll_tag is not None:
                  spans.add((active_conll_tag, (span_start, span_end)))
              active_conll_tag = None
              # We don't care about tags we are
              # told to ignore, so we do nothing.
              continue
          elif bio_tag == "B":
              # We are entering a new span; reset indices
              # and active tag to new span.
              if active_conll_tag is not None:
                  spans.add((active_conll_tag, (span_start, span_end)))
              active_conll_tag = conll_tag
              span_start = index
              span_end = index
          elif bio_tag == "I" and conll_tag == active_conll_tag:
              # We're inside a span.
              span_end += 1
          else:
              # This is the case the bio label is an "I", but either:
              # 1) the span hasn't started - i.e. an ill formed span.
              # 2) The span is an I tag for a different conll annotation.
              # We'll process the previous span if it exists, but also
              # include this span. This is important, because otherwise,
              # a model may get a perfect F1 score whilst still including
              # false positive ill-formed spans.
              if active_conll_tag is not None:
                  spans.add((active_conll_tag, (span_start, span_end)))
              active_conll_tag = conll_tag
              span_start = index
              span_end = index
      # Last token might have been a part of a valid span.
      if active_conll_tag is not None:
          spans.add((active_conll_tag, (span_start, span_end)))
      return list(spans)
  
file_path: allennlp/allennlp/data/dataset_readers/dataset_utils/span_utils.py
imports: from typing import Callable, List, Set, Tuple, TypeVar, Optional
  import warnings
  from allennlp.common.checks import ConfigurationError
  from allennlp.data.tokenizers import Token
label_desc: Use image node_id 2 for calling a global function with example usage: bio_tags_to_spans(tag_sequence, classes_to_ignore) and returns: list