"""辅助表格.
"""
import copy
from typing import List, Any, Optional
class Table:
"""表格处理, 减少对其他外部库依赖
"""
@staticmethod
def table(datas: List[List[Any]], headers: Optional[List[Any]] = None, col_width_max: int = 128,
auto_sort: bool = True) -> str:
"""获取格式化的表格字符串
:param datas: 二维表格数据,每个子列表代表一行
:param headers: 可选表头列表
:param col_width_max: 单列最大列宽
:param auto_sort: 自动升序排序
:return: 格式化后的网格表格字符串
"""
_heads = None if headers is None else copy.deepcopy(headers)
_datas = copy.deepcopy(datas)
if _heads is not None:
_datas.append(_heads)
col_num = max(len(row) for row in _datas)
col_widths = [0] * col_num
for i, row in enumerate(_datas):
if len(row) < col_num:
_datas[i] = row + [""] * (col_num - len(row))
row = _datas[i]
for j, col in enumerate(row):
col_widths[j] = max(col_widths[j], len(str(col)))
if _heads is not None:
_datas = _datas[:-1]
if auto_sort:
_datas.sort(reverse=False)
separator = Table._make_separator(widths=col_widths, width_max=col_width_max, div='-')
lines = []
if headers is not None:
lines.append(separator)
lines.append(Table._make_details(widths=col_widths, datas=_heads, width_max=col_width_max))
lines.append(Table._make_separator(widths=col_widths, width_max=col_width_max, div='='))
else:
lines.append(separator)
for row in _datas:
lines.append(Table._make_details(widths=col_widths, datas=row, width_max=col_width_max, mode="left"))
lines.append(separator)
return "\n" + "\n".join(lines)
@staticmethod
def _make_separator(widths: List[int], width_max: int = 128, cross: str = '+', div: str = '-') -> str:
"""构建分隔线
:param widths: 各列的列宽
:param width_max: 单列最大列宽
:param cross: 交叉点字符
:param div: division 行中某元素点字符
:return 分割线字符串
"""
line = cross
for width in widths:
width = min(width, width_max)
line += div * (width + 2) + cross
return line
@staticmethod
def _make_details(widths: List[int], datas: List[Any], width_max: int = 128, mode: str = "center") -> str:
"""构建数据行详细信息
:param widths: 各列的列宽
:param width_max: 单列最大列宽
:param datas: 单行各元素
:param mode: 单元素对齐方式
:return: 数据行字符串
"""
line = "|"
mode = mode.lower()
for idx, ele in enumerate(datas):
ele = str(ele)
if mode in ["right", "r"]:
ele = ele.rjust(widths[idx])
elif mode in ["left", "l"]:
ele = ele.ljust(widths[idx])
else:
ele = ele.center(widths[idx])
ele = ele[:width_max]
line += f" {ele} |"
return line