Extracts durations tokens from a duration representation.

    Parses the string representation incrementaly and raises
    on first error met.

    :param  representation: duration representation
    :type   representation: string

def extract_tokens(representation, separators=SEPARATOR_CHARACTERS):
    """Extracts durations tokens from a duration representation.

    Parses the string representation incrementaly and raises
    on first error met.

    :param  representation: duration representation
    :type   representation: string
    """
    buff = ""
    elements = []
    last_index = 0
    last_token = None

    for index, c in enumerate(representation):
        # if separator character is found, push
        # the content of the buffer in the elements list
        if c in separators:
            if buff:
                # If the last found token is invalid,
                # raise and InvalidTokenError
                if not valid_token(buff):
                    raise InvalidTokenError(
                        "Duration representation {0} contains "
                        "an invalid token: {1}".format(representation, buff)
                    )

                # If buffer content is a separator word, for example
                # "and", just ignore it
                if not buff.strip() in SEPARATOR_TOKENS:
                    elements.append(buff)

            # Anyway, reset buffer and last token marker
            # to their zero value
            buff = ""
            last_token = None
        else:
            token = compute_char_token(c)
            if (token is not None and last_token is not None and token != last_token):
                elements.append(buff)
                buff = c
            else:
                buff += c

            last_token = token

    # push the content left in representation
    # in the elements list
    elements.append(buff)

    return list(zip(elements[::2], elements[1::2]))