from typing import List
import re


def split_authors(authors: str) -> List:
    """
    Split author string into authors entity lists.

    Take an author line as a string and return a reference to a list of the
    different name and affiliation blocks. While this does normalize spacing
    and 'and', it is a key feature that the set of strings returned can be
    concatenated to reproduce the original authors line. This code thus
    provides a very graceful degredation for badly formatted authors lines, as
    the text at least shows up.
    """
    # split authors field into blocks with boundaries of ( and )
    if not authors:
        return []
    aus = re.split(r'(\(|\))', authors)
    aus = list(filter(lambda x: x != '', aus))

    blocks = []
    if len(aus) == 1:
        blocks.append(authors)
    else:
        c = ''
        depth = 0
        for bit in aus:
            if bit == '':
                continue
            if bit == '(':  # track open parentheses
                depth += 1
                if depth == 1:
                    blocks.append(c)
                    c = '('
                else:
                    c = c + bit
            elif bit == ')':  # track close parentheses
                depth -= 1
                c = c + bit
                if depth == 0:
                    blocks.append(c)
                    c = ''
                else:  # haven't closed, so keep accumulating
                    continue
            else:
                c = c + bit
        if c:
            blocks.append(c)

    listx = []

    for block in blocks:
        block = re.sub(r'\s+', ' ', block)
        if re.match(r'^\(', block):  # it is a comment
            listx.append(block)
        else:  # it is a name
            block = re.sub(r',?\s+(and|\&)\s', ',', block)
            names = re.split(r'(,|:)\s*', block)
            for name in names:
                if not name:
                    continue
                name = name.rstrip().lstrip()
                if name:
                    listx.append(name)

    # Recombine suffixes that were separated with a comma
    parts: List[str] = []
    for p in listx:
        if re.match(r'^(Jr\.?|Sr\.?\[IV]{2,})$', p) \
                and len(parts) >= 2 \
                and parts[-1] == ',' \
                and not re.match(r'\)$', parts[-2]):
            separator = parts.pop()
            last = parts.pop()
            recomb = "{}{} {}".format(last, separator, p)
            parts.append(recomb)
        else:
            parts.append(p)

    return parts