def ParseTab(page, bbox, columns = None):
tab_rect = fitz.Rect(bbox).irect<EOL>xmin, ymin, xmax, ymax = tuple(tab_rect)<EOL>if tab_rect.isEmpty or tab_rect.isInfinite:<EOL><INDENT>print("<STR_LIT>")<EOL>return []<EOL><DEDENT>if type(columns) is not list or columns == []:<EOL><INDENT>coltab = [tab_rect.x0, tab_rect.x1]<EOL><DEDENT>else:<EOL><INDENT>coltab = sorted(columns)<EOL><DEDENT>if xmin < min(coltab):<EOL><INDENT>coltab.insert(<NUM_LIT:0>, xmin)<EOL><DEDENT>if xmax > coltab[-<NUM_LIT:1>]:<EOL><INDENT>coltab.append(xmax)<EOL><DEDENT>words = page.getTextWords()<EOL>if words == []:<EOL><INDENT>print("<STR_LIT>")<EOL>return []<EOL><DEDENT>alltxt = []<EOL>for w in words:<EOL><INDENT>ir = fitz.Rect(w[:<NUM_LIT:4>]).irect         <EOL>if ir in tab_rect:<EOL><INDENT>cnr = <NUM_LIT:0>                         <EOL>for i in range(<NUM_LIT:1>, len(coltab)): <EOL><INDENT>if ir.x0 < coltab[i]:       <EOL><INDENT>cnr = i - <NUM_LIT:1><EOL>break<EOL><DEDENT><DEDENT>alltxt.append([ir.x0, ir.y0, ir.x1, cnr, w[<NUM_LIT:4>]])<EOL><DEDENT><DEDENT>if alltxt == []:<EOL><INDENT>print("<STR_LIT>")<EOL>return []<EOL><DEDENT>alltxt.sort(key = itemgetter(<NUM_LIT:1>))        <EOL>spantab = []                            <EOL>for y, zeile in groupby(alltxt, itemgetter(<NUM_LIT:1>)):<EOL><INDENT>schema = ["<STR_LIT>"] * (len(coltab) - <NUM_LIT:1>)<EOL>for c, words in groupby(zeile, itemgetter(<NUM_LIT:3>)):<EOL><INDENT>entry = "<STR_LIT:U+0020>".join([w[<NUM_LIT:4>] for w in words])<EOL>schema[c] = entry<EOL><DEDENT>spantab.append(schema)<EOL><DEDENT>return spantab<EOL>
Returns the parsed table of a page in a PDF / (open) XPS / EPUB document.
    Parameters:
    page: fitz.Page object
    bbox: containing rectangle, list of numbers [xmin, ymin, xmax, ymax]
    columns: optional list of column coordinates. If None, columns are generated
    Returns the parsed table as a list of lists of strings.
    The number of rows is determined automatically
    from parsing the specified rectangle.