Q:

Pythonic solution to display multi-dimensional tuple as a tree

I would like to show the tree-like structure contained in a multi-dimensional tuple by using the set of graphical glyphs that exist in Unicode fonts (e.g. \u2500, \u2502, \u2514 and others). Here is an example of the kind of output, I'm talking about:
>>> showtree('(01, (02,  03, 04), 05, ((06, 07), 08), (09, (10, 11), (12, 13), 14), 15)')
┬─01
├─┬─02
│ ├─03
│ └─04
├─05
├─┬─┬─06
│ │ └─07
│ └─08
├─┬─09
│ ├─┬─10
│ │ └─11
│ ├─┬─12
│ │ └─13
│ └─14
└─15

Ideally, empty items, multi-words items, extra spaces around commas or parenthesis, as well as unbalanced parenthesis should be managed correctly, as in the following example:
>>> showtree('( A, B multi-word item , (C,D), ( E  , ,  F ), G  )'))
┬─A
├─B multi-word item
├─┬─C
│ └─D
├─┬─E
│ ├─
│ └─F
└─G

I came up with a solution that works quite well (the examples above have been generated with it) but the implemented algorithm is not very elegant, and the code not very pythonic :
def showtree(string):
    """display multidimensional tuple as a tree"""
    glyphs = ['\u252C\u2500','\u251C\u2500','\u2514\u2500','\u2502 ']
    tree, glyph, item = [], [], []
    for char in string:
        if char in ',)' and item:                                   # add glyph prefix and current item to tree
            tree.append(glyph + [''.join(item).strip()]); item = []
        if char == ',':                                             # update glyph prefix for new item in sublist
            glyph = [glyphs[3]] * (len(glyph)-1) + [glyphs[1]]
        elif char == ')':                                           # update glyph prefix for last item in sublist
            tree[-1][-2] = glyphs[2]; glyph = glyph[:-1] 
        elif char == '(':                                           # update glyph prefix for first item in sublist
            glyph.append(glyphs[0])
        else:                                                       # other chars are simply added to current item
            item.append(char)
    return '\n'.join(''.join(node) for node in tree)

So I would like to get some ideas for an improved implementation, maybe using regular expressions or other advanced parsing techniques. Thank you very much for any hint...

A:

Neither the code provided in the question or the top voted answer work correctly. This is as you're making unreasonable assumptions on how the data is formed.
>>> print(showtree('(A)'))
└─A
>>> print(showtree('(1, ((2)), (3, 4, (5)))'))
┬─1
├─┬─└─2
├─┬─3
│ ├─4
│ ├─└─5
>>> print(tree_string_to_display_string('(1, ((2)), (3, 4, (5)))'))
┬─1
├─┬─└─2
├─┬─3
│ ├─4
│ ├─└─5

Your code is also doing two things at once, parsing a string and building a tree. And so I will only take a tuple as input. If you need to take a string then you can build the parser separately.

Make the code work with one item.
To do this should be fairly simple, we take the tuple ('1',) and return ──1.
def build_tree(root):
    return '\n'.join(_build_tree(root))

def _build_tree(node):
    yield '──' + node[0]

>>> print(build_tree(('1',)))
──1

Make the code work with 1, 2 or more items.
This is fairly simple, we check node's length and use the above code if it's 1. Otherwise we make:

The first item start with ┬─.
The last item start with └─.
All other items start with ├─.

This is as simple as using tuple unpacking, and then iterating over the middle.
def _build_tree(node):
    if len(node) == 1:
        yield '──' + node[0]
        return

    start, *mid, end = node
    yield '┬─' + start
    for value in mid:
        yield '├─' + value
    yield '└─' + end

>>> print(build_tree(('1',)))
──1
>>> print(build_tree(('1', '2')))
┬─1
└─2
>>> print(build_tree(('1', '2', '3')))
┬─1
├─2
└─3

Get the code to work if you only enter a value, no tuples.
This is simple, since we're only allowing tuples as the nesting datatype, then we can just add an if not isinstance(node, tuple). We will convert this to a string now to help our future selves.
def _build_tree(node):
    if not isinstance(node, tuple):
        yield str(node)
        return

    if len(node) == 1:
        yield '──' + node[0]
        return

    start, *mid, end = node
    yield '┬─' + start
    for value in mid:
        yield '├─' + value
    yield '└─' + end

>>> print(build_tree('1'))
1

Get the code to work recursively with the same input as (2). To check this we will change the input to integers.
This is simple. We run _build_tree on all the values in node, if it's a tuple. From here we only work on these values. We know these values are going to be iterators with only one value. This means we can just use next for now.
def _build_tree(node):
    if not isinstance(node, tuple):
        yield str(node)
        return

    values = [_build_tree(n) for n in node]
    if len(values) == 1:
        yield '──' + next(values[0])
        return

    start, *mid, end = values
    yield '┬─' + next(start)
    for value in mid:
        yield '├─' + next(value)
    yield '└─' + next(end)

>>> print(build_tree((1,)))
──1
>>> print(build_tree((1, 2)))
┬─1
└─2
>>> print(build_tree((1, 2, 3)))
┬─1
├─2
└─3

Get the code working recursively.
We know all the current yields work the same way, and so this calls for a new function. This should take three values:

The value to add to the first item. (This is what we're doing right now)
The value to add on all other items.
This is important as if a node is only one large. But has nested data that is larger than one value then we will add '  ' to the output.
The nested data.

This is really simple to build:
def build_lines(first, other, values):
    yield first + next(values)
    for value in values:
        yield other + value

Finally we adjust the current yields so they are yield from functions.

def build_tree(root):
    return '\n'.join(_build_tree(root))

def _build_tree(node):
    if not isinstance(node, tuple):
        yield str(node)
        return

    values = [_build_tree(n) for n in node]
    if len(values) == 1:
        yield from build_lines('──', '  ', values[0])
        return

    start, *mid, end = values
    yield from build_lines('┬─', '│ ', start)
    for value in mid:
        yield from build_lines('├─', '│ ', value)
    yield from build_lines('└─', '  ', end)

def build_lines(first, other, values):
    yield first + next(values)
    for value in values:
        yield other + value

>>> print(build_tree(('01', ('02',  '03', '04'), '05', (('06', '07'), '08'), ('09', ('10', '11'), ('12', '13'), '14'), '15')))
┬─01
├─┬─02
│ ├─03
│ └─04
├─05
├─┬─┬─06
│ │ └─07
│ └─08
├─┬─09
│ ├─┬─10
│ │ └─11
│ ├─┬─12
│ │ └─13
│ └─14
└─15
>>> print(build_tree(('A', 'B multi-word item', ('C', 'D'), ('E', '', 'F'), 'G')))
┬─A
├─B multi-word item
├─┬─C
│ └─D
├─┬─E
│ ├─
│ └─F
└─G
>>> print(build_tree((1, ((2,),), (3, 4, (5,)))))
┬─1
├─────2
└─┬─3
  ├─4
  └───5

