python 生成复杂表格,自动分页等功能

python 生成复杂表格,自动分页等功能

解决将Python中的树形目录数据转换为Word表格,并生成带有合并单元格的检测报告的问题。首先,要解决“tree目录数据”和“Word表格互换”,指将树形结构的数据转换成Word表格,并在转换过程中合并相应的单元格以反映层次结构。此外,还有自动分页和固定表头的问题,现在可能希望生成的报告能够自动处理这些格式问题。

首先,我需要明确树形目录数据的结构。通常,树形结构有父子节点关系,比如文件夹结构,每个节点可能有名称、类型、大小、修改日期等属性。希望将这些层次结构在Word表格中展示,通过合并单元格来表示父子关系,例如,一个父节点占据一行,其子节点在下方缩进显示,可能需要合并某些列来体现层级。

在Python中,处理树形结构通常使用递归。对于每个节点,可能需要确定其在表格中的行位置,并根据层级决定合并哪些单元格。例如,根节点可能需要合并所有列的一行,子节点可能只在第一列显示名称,后面的列合并或留空,或者根据具体需求调整。

生成Word文档需要使用python-docx库。该库允许创建表格、设置样式、合并单元格等操作。关键点是如何遍历树形数据并动态生成表格行,同时处理合并单元格的逻辑。可能需要为每个节点计算其在表格中的行数和列数,特别是当子节点存在时,父节点可能需要跨多行合并。

以下是试验代码

from docx import Document
from docx.shared import Pt, Cm
from docx.enum.table import WD_TABLE_ALIGNMENT
from docx.oxml.shared import OxmlElement, qn
import randomclass TreeNode:def __init__(self, name, depth=0, is_file=False, size=0, parent=None):self.name = nameself.depth = depthself.is_file = is_fileself.size = f"{size} KB" if is_file else ""self.parent = parentself.children = []self.start_row = 0self.end_row = 0self.col_span = 1  # 新增横向合并跨度class EnhancedDirectoryReport:def __init__(self, filename):self.doc = Document()self.filename = filenameself._setup_document()self.table = Noneself.current_row = 0self.column_map = ['一级目录', '二级目录', '三级目录', '文件名', '路径', '大小']self.current_table = Noneself.current_page_rows = 0self.max_page_rows = 35  # 根据实际内容调整每页行数self.active_directory = {}  # 记录当前活跃的目录层级def _setup_document(self):section = self.doc.sections[0]margins = {'left': 2, 'right': 2, 'top': 2.5, 'bottom': 2.5}for attr, cm_val in margins.items():setattr(section, f"{attr}_margin", Cm(cm_val))style = self.doc.styles['Normal']style.font.name = '微软雅黑'style.font.size = Pt(10)def _create_new_page(self):"""创建新页面并初始化表格"""if self.current_table is not None:self.doc.add_page_break()self.current_table = self.doc.add_table(rows=0, cols=6)self.current_table.style = 'Table Grid'widths = [Cm(3.5), Cm(3.5), Cm(3.5), Cm(4), Cm(6), Cm(2.5)]for idx, w in enumerate(widths):self.current_table.columns[idx].width = wself._create_table_header()print('建表头后',self.current_row,self.current_page_rows)self.current_page_rows = 1  # 表头占1行# 重新应用活跃目录self._reapply_active_directory()def _reapply_active_directory(self):"""在新页重新应用当前活跃目录"""for depth in [1, 2, 3]:if depth in self.active_directory:node = self.active_directory[depth]self._add_directory_row(node, depth)def _add_directory_row(self, node, depth):"""添加目录行并更新活跃状态"""row = self.current_table.add_row()cells = row.cells# 填充目录信息cells[depth - 1].text = node.namecells[depth - 1].paragraphs[0].alignment = WD_TABLE_ALIGNMENT.LEFT# 设置跨列合并if depth == 1:cells[0].merge(cells[5])elif depth == 2:cells[1].merge(cells[5])elif depth == 3:cells[2].merge(cells[5])# 更新活跃目录self.active_directory[depth] = nodeself.current_page_rows += 1def _check_page_break(self):"""检查是否需要分页"""if self.current_page_rows >= self.max_page_rows:self._create_new_page()print('分页')def _add_file_row(self, node):"""添加文件行"""self._check_page_break()row = self.current_table.add_row()cells = row.cells# 填充文件信息cells[3].text = node.namecells[4].text = self._get_full_path(node)cells[5].text = node.size# 继承活跃目录for depth in [1, 2, 3]:if depth in self.active_directory:cells[depth - 1].text = self.active_directory[depth].namecells[depth - 1].paragraphs[0].alignment = WD_TABLE_ALIGNMENT.CENTERself.current_page_rows += 1def _get_full_path(self, node):path = []current = node.parentwhile current and current.depth > 0:path.insert(0, current.name)current = current.parentreturn '/' + '/'.join(path)def process_structure(self, root):"""处理目录结构"""self._create_new_page()stack = [(root, False)]  # (node, visited)while stack:node, visited = stack.pop()if visited:# 后序遍历处理合并if not node.is_file:self._update_active_directory(node)continueif node.is_file:self._add_file_row(node)else:# 前序遍历添加目录self._check_page_break()self._add_directory_row(node, node.depth)stack.append((node, True))# 逆向添加子节点以保持顺序for child in reversed(node.children):stack.append((child, False))self.doc.save(self.filename)def _update_active_directory(self, node):"""更新活跃目录状态"""# 清除子目录状态for depth in list(self.active_directory.keys()):if depth > node.depth:del self.active_directory[depth]def _create_table_header(self):header = self.table.add_row()for idx, text in enumerate(self.column_map):cell = header.cells[idx]cell.text = textcell.paragraphs[0].runs[0].font.bold = Truecell.paragraphs[0].alignment = WD_TABLE_ALIGNMENT.CENTERself._set_cell_color(cell, 'A3D3D3')tr = header._trtrPr = tr.get_or_add_trPr()tblHeader = OxmlElement('w:tblHeader')tblHeader.set(qn('w:val'), "true")trPr.append(tblHeader)print(self.current_row)self.current_row += 1def _set_cell_color(self, cell, hex_color):shading = OxmlElement('w:shd')shading.set(qn('w:fill'), hex_color)cell._tc.get_or_add_tcPr().append(shading)def _smart_merge(self, node):"""智能合并策略核心方法"""# 垂直合并处理if node.depth <= 3 and not node.is_file:self._vertical_merge(node)# 横向合并处理if node.depth == 1 and not any(not c.is_file for c in node.children):self._horizontal_merge(node, 1, 3)  # 一级目录合并到文件名列if node.depth == 2 and not any(not c.is_file for c in node.children):self._horizontal_merge(node, 2, 3)  # 二级目录合并到文件名列def _horizontal_merge(self, node, start_col, end_col):"""安全横向合并方法"""for row_idx in range(node.start_row, node.end_row):# 获取需要合并的单元格print('nc ', row_idx, start_col, end_col)start_cell = self.table.cell(row_idx, start_col)end_cell = self.table.cell(row_idx, end_col)print(row_idx, start_col, end_col)print('开结',start_cell, end_cell)# 检查是否已经被合并if start_cell._element is end_cell._element:print('已合并过')continueelse:start_cell.merge(end_cell)def _vertical_merge(self, node):"""垂直方向合并"""if node.start_row >= node.end_row:returndepth_col_map = {1: 0, 2: 1, 3: 2}col_idx = depth_col_map.get(node.depth)if col_idx is not None:try:start_cell = self.table.cell(node.start_row, col_idx)end_cell = self.table.cell(node.end_row - 1, col_idx)start_cell.merge(end_cell)start_cell.text = node.nameexcept IndexError as e:print(f"垂直合并失败:{node.name}")raise edef _fill_row_data(self, node):"""填充数据并设置合并策略"""row = self.table.add_row()cells = row.cells# 文件信息if node.is_file:cells[3].text = node.namecells[4].text = self._get_full_path(node)cells[5].text = node.size# else:#     # 设置目录层级#     for d in range(1, 4):#         print(d, cells[d])#         print(node.name, node.depth)#         if node.depth == d:#             cells[d - 1].text = node.name#             # if d < 3:#             #     cells[d].merge(cells[d])# 设置样式for cell in cells:cell.vertical_alignment = WD_TABLE_ALIGNMENT.CENTERself.current_row += 1return row# def _get_full_path(self, node):#     path = []#     current = node.parent#     while current and current.depth > 0:#         path.insert(0, current.name)#         current = current.parent#     return '/' + '/'.join(path) + ('' if node.is_file else f'/{node.name}')def _process_node(self, node):node.start_row = self.current_row#增限制,如为净空不加行if node.depth > 1 and node.is_file:self._fill_row_data(node)for child in node.children:self._process_node(child)node.end_row = self.current_rowself._smart_merge(node)def generate_report(self, root):self.table = self.doc.add_table(rows=0, cols=6)self.table.style = 'Table Grid'widths = [Cm(3.5), Cm(3.5), Cm(3.5), Cm(4), Cm(6), Cm(2.5)]for idx, w in enumerate(widths):self.table.columns[idx].width = w# self._create_table_header()self._create_new_page()self._process_node(root)print(self.doc.tables)self.doc.save(self.filename)# 测试数据生成器
class TestDataGenerator:@staticmethoddef create_large_structure():root = TreeNode("ROOT", depth=0)# 一级目录(10个)for i in range(1, 11):dir1 = TreeNode(f"一级目录_{i}", depth=1, parent=root)root.children.append(dir1)# 30%概率没有子目录if random.random() < 0.3:# 直接添加文件for j in range(random.randint(2, 5)):file = TreeNode(f"文件_{i}-{j}.docx", depth=4,is_file=True,size=random.randint(100, 5000),parent=dir1)dir1.children.append(file)continue# 二级目录(每个一级目录3-5个)for j in range(random.randint(3, 5)):dir2 = TreeNode(f"二级目录_{i}-{j}", depth=2, parent=dir1)dir1.children.append(dir2)# 50%概率没有三级目录if random.random() < 0.5:# 直接添加文件for k in range(random.randint(3, 6)):file = TreeNode(f"文件_{i}-{j}-{k}.xlsx", depth=4,is_file=True,size=random.randint(100, 5000),parent=dir2)dir2.children.append(file)continue# 三级目录(每个二级目录2-4个)for k in range(random.randint(2, 4)):dir3 = TreeNode(f"三级目录_{i}-{j}-{k}", depth=3, parent=dir2)dir2.children.append(dir3)# 添加文件for m in range(random.randint(3, 8)):file = TreeNode(f"文件_{i}-{j}-{k}-{m}.pptx", depth=4,is_file=True,size=random.randint(100, 5000),parent=dir3)dir3.children.append(file)return rootif __name__ == '__main__':# 生成测试数据data_generator = TestDataGenerator()root_node = data_generator.create_large_structure()# 生成报告report = EnhancedDirectoryReport("上下左右目录2.docx")report.generate_report(root_node)

效果如图所示:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/pingmian/82556.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

根据Cortex-M3(包括STM32F1)权威指南讲解MCU内存架构与如何查看编译器生成的地址具体位置

首先我们先查看官方对于Cortex-M3预定义的存储器映射 1.存储器映射 1.1 Cortex-M3架构的存储器结构 内部私有外设总线&#xff1a;即AHB总线&#xff0c;包括NVIC中断&#xff0c;ITM硬件调试&#xff0c;FPB, DWT。 外部私有外设总线&#xff1a;即APB总线&#xff0c;用于…

Linux中硬件信息查询利器——lshw命令详解!

lshw&#xff08;List Hardware&#xff09;是 Linux 系统下的一款命令行工具&#xff0c;用于全面检测并显示详细的硬件信息。它能够报告 CPU、内存、主板、存储设备、显卡、网络设备等几乎所有硬件组件的详细信息&#xff0c;适用于系统管理、故障排查和硬件兼容性检查等场景…

用llama3微调了一个WiFiGPT 用于室内定位

一段话总结 本文提出WiFiGPT,一种基于Decoder-Only Transformer(如LLaMA 3)的室内定位系统,通过将WiFi遥测数据(如CSI、FTM、RSSI)转换为文本序列进行端到端训练,无需手工特征工程即可实现高精度定位。实验表明,WiFiGPT在LOS环境中实现亚米级精度(MAE低至0.90米),在…

大模型系列22-MCP

大模型系列22-MCP 玩转 MCP 协议&#xff1a;用 Cline DeepSeek 接入天气服务什么是 MCP&#xff1f;环境准备&#xff1a;VScode Cline DeepSeek**配置 DeepSeek 模型&#xff1a;****配置 MCP 工具****uvx是什么&#xff1f;****安装 uv&#xff08;会自动有 uvx 命令&…

Go语言Map的底层原理

概念 map 又称字典&#xff0c;是一种常用的数据结构&#xff0c;核心特征包含下述三点&#xff1a; &#xff08;1&#xff09;存储基于 key-value 对映射的模式&#xff1b; &#xff08;2&#xff09;基于 key 维度实现存储数据的去重&#xff1b; &#xff08;3&#x…

循环神经网络(RNN):原理、架构与实战

循环神经网络&#xff08;Recurrent Neural Network, RNN&#xff09;是一类专门处理序列数据的神经网络&#xff0c;如时间序列、自然语言、音频等。与前馈神经网络不同&#xff0c;RNN 引入了循环结构&#xff0c;能够捕捉序列中的时序信息&#xff0c;使模型在不同时间步之间…

java 项目登录请求业务解耦模块全面

登录是统一的闸机&#xff1b; 密码存在数据库中&#xff0c;用的是密文&#xff0c;后端加密&#xff0c;和数据库中做对比 1、UserController public class UserController{Autowiredprivate IuserService userservicepublic JsonResult login(Validated RequestBody UserLo…

【手写数据库核心揭秘系列】第9节 可重入的SQL解析器,不断解析Structure Query Language,语言翻译好帮手

可重入的SQL解析器 文章目录 可重入的SQL解析器一、概述 二、可重入解析器 2.1 可重入设置 2.2 记录状态的数据结构 2.3 节点数据类型定义 2.4 头文件引用 三、调整后的程序结构 四、总结 一、概述 现在就来修改之前sqlscanner.l和sqlgram.y程序,可以不断输入SQL语句,循环执…

微软开源bitnet b1.58大模型,应用效果测评(问答、知识、数学、逻辑、分析)

微软开源bitnet b1.58大模型,应用效果测评(问答、知识、数学、逻辑、分析) 目 录 1. 前言... 2 2. 应用部署... 2 3. 应用效果... 3 1.1 问答方面... 3 1.2 知识方面... 4 1.3 数字运算... 6 1.4 逻辑方面... …

用HTML5+JavaScript实现汉字转拼音工具

用HTML5JavaScript实现汉字转拼音工具 前一篇博文&#xff08;https://blog.csdn.net/cnds123/article/details/148067680&#xff09;提到&#xff0c;当需要将拼音添加到汉字上面时&#xff0c;用python实现比HTML5JavaScript实现繁琐。在这篇博文中用HTML5JavaScript实现汉…

鸿蒙OSUniApp 开发的动态背景动画组件#三方框架 #Uniapp

使用 UniApp 开发的动态背景动画组件 前言 在移动应用开发中&#xff0c;动态背景动画不仅能提升界面美感&#xff0c;还能增强用户的沉浸感和品牌辨识度。无论是登录页、首页还是活动页&#xff0c;恰到好处的动态背景都能让产品脱颖而出。随着鸿蒙&#xff08;HarmonyOS&am…

云原生技术架构技术探索

文章目录 前言一、什么是云原生技术架构二、云原生技术架构的优势三、云原生技术架构的应用场景结语 前言 在当今的技术领域&#xff0c;云原生技术架构正以一种势不可挡的姿态席卷而来&#xff0c;成为了众多开发者、企业和技术爱好者关注的焦点。那么&#xff0c;究竟什么是…

AWS之AI服务

目录 一、AWS AI布局 ​​1. 底层基础设施与芯片​​ ​​2. AI训练框架与平台​​ ​​3. 大模型与应用层​​ ​​4. 超级计算与网络​​ ​​与竞品对比​​ AI服务 ​​1. 机器学习平台​​ ​​2. 预训练AI服务​​ ​​3. 边缘与物联网AI​​ ​​4. 数据与AI…

lwip_bind、lwip_listen 是阻塞函数吗

在 lwIP 协议栈中&#xff0c;lwip_bind 和 lwip_listen 函数本质上是非阻塞的。 通常&#xff0c;bind和listen在大多数实现中都是非阻塞的&#xff0c;因为它们只是设置套接字的属性&#xff0c;不需要等待外部事件。阻塞通常发生在接受连接&#xff08;accept&#xff09;、…

【后端高阶面经:消息队列篇】28、从零设计高可用消息队列

一、消息队列架构设计的核心目标与挑战 设计高性能、高可靠的消息队列需平衡功能性与非功能性需求,解决分布式系统中的典型问题。 1.1 核心设计目标 吞吐量:支持百万级消息/秒处理,通过分区并行化实现横向扩展。延迟:端到端延迟控制在毫秒级,适用于实时业务场景。可靠性…

【运维实战】Linux 内存调优之进程内存深度监控

写在前面 内容涉及 Linux 进程内存监控 监控方式包括传统工具 ps/top/pmap ,以及 cgroup 内存子系统&#xff0c;proc 内存伪文件系统 监控内容包括进程内存使用情况&#xff0c; 内存全局数据统计&#xff0c;内存事件指标&#xff0c;以及进程内存段数据监控 监控进程的内…

决策树 GBDT XGBoost LightGBM

一、决策树 1. 决策树有一个很强的假设&#xff1a; 信息是可分的&#xff0c;否则无法进行特征分支 2. 决策树的种类&#xff1a; 2. ID3决策树&#xff1a; ID3决策树的数划分标准是信息增益&#xff1a; 信息增益衡量的是通过某个特征进行数据划分前后熵的变化量。但是&…

java基础学习(十四)

文章目录 4-1 面向过程与面向对象4-2 Java语言的基本元素&#xff1a;类和对象面向对象的思想概述 4-3 对象的创建和使用内存解析匿名对象 4-1 面向过程与面向对象 面向过程(POP) 与 面向对象(OOP) 二者都是一种思想&#xff0c;面向对象是相对于面向过程而言的。面向过程&…

TCP 三次握手,第三次握手报文丢失会发生什么?

文章目录 RTO(Retransmission Timeout)注意 客户端收到服务端的 SYNACK 报文后&#xff0c;会回给服务端一个 ACK 报文&#xff0c;之后处于 ESTABLISHED 状态 因为第三次握手的 ACK 是对第二次握手中 SYN 的确认报文&#xff0c;如果第三次握手报文丢失了&#xff0c;服务端就…

deepseek告诉您http与https有何区别?

有用户经常问什么是Http , 什么是Https &#xff1f; 两者有什么区别&#xff0c;下面为大家介绍一下两者的区别 一、什么是HTTP HTTP是一种无状态的应用层协议&#xff0c;用于在客户端浏览器和服务器之间传输网页信息&#xff0c;默认使用80端口 二、HTTP协议的特点 HTTP协议…