def _txt_tabular(columns, titles=None, separator=''):
    """Tabularises a list of lists, with the option of including titles.
    Used in textfile outputs.

    Parameters
    ----------
    columns : list
        A list of lists, with each sublist representing the columns of the
        table. Each list must be of the same length.

    titles : None or list, default: None
        Titles for the table. If desired, `titles` should be of the same
        length as all of the sublists in `columns`.

    separator : str, default: ''
        Column separator. By default, an empty string is used. (See first
        example above).

    Returns
    -------
    table : str
        A string with the contents of `titles` (opt.) and `columns`
        tabularised.

    Examples
    --------
    A simple example with `titles` specified and the default `separator`:

    .. code:: python3

       >>> from nmrespy.write import _txt_tabular
       >>> columns = [['A1', 'B1'], ['A2', 'B2'], ['A3', 'B3']]
       >>> titles = ['title 1', 'title 2', 'title 3']
       >>> print(_txt_tabular(columns, titles=titles))
       title 1  title 2  title 3
       ────────┼────────┼────────
       A1       A2       A3
       B1       B2       B3

    You may want to set `separator` to something like ``'│'``
    in order for a nicer layout when you have titles:

    .. code:: python3

       >>> # Same as before...
       >>> print(_txt_tabular(columns, titles=titles, separator='│'))
       title 1 │title 2 │title 3
       ────────┼────────┼────────
       A1      │A2      │A3
       B1      │B2      │B3
    """
    # If titles are given, append to the top of each column
    if titles:
        for i, (title, column) in enumerate(zip(titles, columns)):
            columns[i] = [title] + column
    # --- Determine width of each column ---------------------------------
    pads = []
    for column in columns:
        # For each column find the longest string, and set its length
        # as the width
        pads.append(max(len(str(element)) for element in column))

    # --- Construct table ------------------------------------------------
    table = ''
    # Iterate of rows (transpose array)
    for i, row in enumerate(zip(*columns)):
        # Iterate over each adjacent pair of elements in row
        for j, (pad, e1, e2) in enumerate(zip(pads, row, row[1:])):
            # Determine amount of padding between pair
            p = pad - len(e1) + 1
            # First element -> don't want any padding before it.
            # All other elements are padded from the left.
            if j == 0:
                # Case for first pairing in row
                table += f"{e1}{p*' '}{separator}{e2}"
            else:
                table += f"{p*' '}{separator}{e2}"
        # Add newline character at end of row
        table = f'{table}\n'

        # At end of the first row, check if titles were given
        # If so, add a horizontal line underneath to separate the titles
        # from the other contents
        if titles and i == 0:
            for k, pad in enumerate(pads):
                p = pad + 1
                # Add a bar that looks like this: '────────┼'
                table += f"{p*'─'}┼"
            # Once the bar has been completed, remove the trailing '┼'
            # and add a newline
            table = f'{table[:-1]}\n'

    return table