jazzband / prettytable

Display tabular data in a visually appealing ASCII table format
https://pypi.org/project/PrettyTable/
Other
1.32k stars 149 forks source link

Calculate column width #260

Closed pkodzis closed 9 months ago

pkodzis commented 9 months ago

I am using PrettyTable to display an ASCII table on a web page. To achieve the desired appearance of an ASCII-like table, I have set a fixed-size font on the website. Everything works as expected until I attempt to change the values in one column from plain text to <a href=...>foo</a>. While this change works, it affects the column widths. PrettyTable calculates the column width based on the entire string when HTML <a> tags are added. Is there a way to force PrettyTable to calculate the column width based on just the "foo" part while still printing "foo"?

hugovk commented 9 months ago

Unfortunately PrettyTable doesn't have a way to do this.

pkodzis commented 9 months ago

fair enough, thsank you for prompt response :)

pkodzis commented 9 months ago

btw, if anybody needs, the code below does what I was looking for:

import re

def html2text(html_str):
    text = re.sub(r'<[^>]*>', '', html_str)
    return text.strip()

def mytable_print(data):
    headers = data[0]
    num_columns = len(headers)

    column_widths = [max(len(html2text(str(row[i])))
                         for row in data) for i in range(num_columns)]

    def print_row(row):
        row_str = ""
        for i in range(num_columns):
            text = str(row[i])
            padding = " " * (column_widths[i] - len(html2text(text)))
            row_str += f"| {text}{padding} "

        print(f"{row_str}|")

    def print_separator():
        separator = "+".join("-" * (width + 2) for width in column_widths)
        print(f"+{separator}+")

    print_separator()
    print_row(headers)
    print_separator()

    for row in data[1:]:
        print_row(row)

    print_separator()

if __name__ == "__main__":
    data = [['OSPF', 'Device', 'Interface', 'IP', 'Neighbor Device', 'Neighbor Interface', 'Neighbor IP', 'Up', 'Adjacency', 'ID', 'Pri', 'Timer', 'State'],
            ['', 'foo', '<a onclick="goJint(event,{\'device\':\'foo\',\'interface\':\'eth0\'});">eth0</a>', '10.10.10.64', 'test1', '<a onclick="goJint(event,{\'device\':\'test1\',\'interface\':\'eth101\'});">eth101</a>', '10.10.10.65', '46w6d 17:12:47', '46w6d 17:12:47', '192.168.1.36', '128', '38', 'Full'],
            ['', 'foo', '<a onclick="goJint(event,{\'device\':\'foo\',\'interface\':\'eth12\'});">eth2</a>', '10.10.10.66', 'test2', '<a onclick="goJint(event,{\'device\':\'test2\',\'interface\':\'vr0\'});">vr0</a>', '10.10.10.67', '46w6d 17:12:45', '46w6d 17:12:45', '192.168.1.37', '128', '31', 'Full']]
    mytable_print(data)
shifenhutu commented 9 months ago

based on @pkodzis , support makrdown link

import re

def html2text(html_str):
    text = re.sub(r'<[^>]*>', '', html_str)
    return text.strip()

def md2text(html_str):
    pattern = r".*\|(\w+)>$"

    match = re.search(pattern, html_str)
    token = html_str
    if match:
        token = match.group(1)

    return token.strip()

def my_PrettyTable(data, type="markdown"):
    """
    支持 markdown 链接 ,html 等 (宽度会适应)
    """
    headers = data[0]
    num_columns = len(headers)

    match type:
        case "markdown":
            fun = md2text
        case "html":
            fun = html2text
        case _:
            fun = md2text

    column_widths = [max(len(fun(str(row[i])))
                         for row in data) for i in range(num_columns)]

    def print_row(row):
        row_str = ""
        for i in range(num_columns):
            text = str(row[i])
            padding = " " * (column_widths[i] - len(fun(text)))
            row_str += f"| {text}{padding} "
        return row_str

    def print_separator():
        separator = "+".join("-" * (width + 2) for width in column_widths)
        # print(f"+{separator}+")
        return f"+{separator}+"

    res = ""
    res = res + print_separator() + "\n"
    res = res + print_row(headers) + "|\n"
    res = res + print_separator() + "\n"

    for row in data[1:]:
        res = res + print_row(row) + "|\n"

    res = res + print_separator()

    return res

if __name__ == "__main__":
    data_html = [['OSPF', 'Device', 'Interface', 'IP', 'Neighbor Device', 'Neighbor Interface', 'Neighbor IP', 'Up', 'Adjacency', 'ID', 'Pri', 'Timer', 'State'],
            ['', 'foo', '<a onclick="goJint(event,{\'device\':\'foo\',\'interface\':\'eth0\'});">eth0</a>', '10.10.10.64', 'test1',
             '<a onclick="goJint(event,{\'device\':\'test1\',\'interface\':\'eth101\'});">eth101</a>', '10.10.10.65', '46w6d 17:12:47', '46w6d 17:12:47', '192.168.1.36', '128', '38', 'Full'],
            ['', 'foo', '<a onclick="goJint(event,{\'device\':\'foo\',\'interface\':\'eth12\'});">eth2</a>', '10.10.10.66', 'test2',
             '<a onclick="goJint(event,{\'device\':\'test2\',\'interface\':\'vr0\'});">vr0</a>', '10.10.10.67', '46w6d 17:12:45', '46w6d 17:12:45', '192.168.1.37', '128', '31', 'Full']]
    html_res = my_PrettyTable(data_html,type="html")

    print(html_res)

    data_md = [['url', 'gt_0', 'zhan_bi'], ['<https://google.com/111|1111111111>', 121, 0.0605], ['<https://google.com/111|111>', 106, 0.053], ['<https://google.com/111|111>', 74, 0.037], ['<https://google.com/111|111>', 72, 0.036], ['<https://google.com/111|111>', 71, 0.0355], ['<https://google.com/111|111>', 57, 0.0285]]
    md_res = my_PrettyTable(data_md, type="markdown")
    print(md_res)