当前位置: 首页 > ds >正文

DeepSeek辅助编写的将xlsx格式文件中sheet1.xml按需分别保留或去掉标签的程序

上文提到,xlsx格式文件中有一些标签属性可选,为了考察不同标签存在时,对程序读取解析性能的影响,需要一个程序来对已有的文件做加工。
交给DeepSeek的提示词如下

wps生成的xlsx中sheet1.xml 标签中有spans="1:cols"标签和r="n"标签(其中cols是总列数,n是数字行号),标签中有r="Bn"其中B是xlsx表格字母列号,n是数字行号)等标签,编写python程序,将sheet.xml中的上述标签分别保留或去掉,形成:
0.无span,无row的r,无col的r
1.有span,无row的r,无col的r
2.有span,有row的r,无col的r
分别输出,保存在子目录0、1、2的同名文件中

例如原始的xml,27340.884122563463474,第0种的要求27340.884122563463474也就是,第1种是27340.884122563463474,第2种是27340.884122563463474

请增加功能,把位于0、1、2目录的sheet1.xml文件替换到xlsx文件解压后的xl/worksheets目录下,xlsx文件中其他目录和文件保持不变,重新压缩生成新的xlsx文件,分别命名为wps0.xlsx,wps1.xlsx,wps2.xlsx。

经过两次修正,得到如下程序

import os
import zipfile
import shutil
import xml.etree.ElementTree as ET
from pathlib import Pathdef process_sheet_xml(input_xlsx_path, output_base_dir):"""处理xlsx文件中的sheet1.xml,生成3种不同标签组合的版本,并重新打包为xlsx文件Args:input_xlsx_path: 输入的xlsx文件路径output_base_dir: 输出文件的基础目录"""# 创建输出目录for i in range(3):os.makedirs(os.path.join(output_base_dir, str(i)), exist_ok=True)# 临时解压目录temp_dir = "temp_extract"os.makedirs(temp_dir, exist_ok=True)try:# 解压xlsx文件with zipfile.ZipFile(input_xlsx_path, 'r') as zip_ref:zip_ref.extractall(temp_dir)# 查找sheet1.xml文件sheet_path = Nonefor root, dirs, files in os.walk(temp_dir):for file in files:if file == "sheet1.xml":sheet_path = os.path.join(root, file)breakif sheet_path:breakif not sheet_path:print("未找到sheet1.xml文件")return# 读取原始XML内容with open(sheet_path, 'r', encoding='utf-8') as f:original_xml = f.read()# 解析XML文件tree = ET.parse(sheet_path)root = tree.getroot()# 处理命名空间namespaces = {'ss': 'http://schemas.openxmlformats.org/spreadsheetml/2006/main'}ET.register_namespace('', namespaces['ss'])# 版本0: 无span, 无row的r, 无col的rversion0 = ET.ElementTree(ET.fromstring(original_xml))for row in version0.findall('.//{http://schemas.openxmlformats.org/spreadsheetml/2006/main}row'):# 移除spans属性if 'spans' in row.attrib:del row.attrib['spans']# 移除r属性if 'r' in row.attrib:del row.attrib['r']# 移除c元素的r属性for cell in row.findall('.//{http://schemas.openxmlformats.org/spreadsheetml/2006/main}c'):if 'r' in cell.attrib:del cell.attrib['r']# 版本1: 有span, 无row的r, 无col的rversion1 = ET.ElementTree(ET.fromstring(original_xml))for row in version1.findall('.//{http://schemas.openxmlformats.org/spreadsheetml/2006/main}row'):# 保留spans属性# 移除r属性if 'r' in row.attrib:del row.attrib['r']# 移除c元素的r属性for cell in row.findall('.//{http://schemas.openxmlformats.org/spreadsheetml/2006/main}c'):if 'r' in cell.attrib:del cell.attrib['r']# 版本2: 有span, 有row的r, 无col的rversion2 = ET.ElementTree(ET.fromstring(original_xml))for row in version2.findall('.//{http://schemas.openxmlformats.org/spreadsheetml/2006/main}row'):# 保留spans属性# 保留r属性# 只移除c元素的r属性for cell in row.findall('.//{http://schemas.openxmlformats.org/spreadsheetml/2006/main}c'):if 'r' in cell.attrib:del cell.attrib['r']# 保存三个版本的sheet1.xml到输出目录output_files = [os.path.join(output_base_dir, "0", "sheet1.xml"),os.path.join(output_base_dir, "1", "sheet1.xml"),os.path.join(output_base_dir, "2", "sheet1.xml")]versions = [version0, version1, version2]for i, (version, output_file) in enumerate(zip(versions, output_files)):# 美化XML格式#indent(version.getroot())# 写入文件version.write(output_file, encoding='utf-8', xml_declaration=True)print(f"版本 {i} 的sheet1.xml已保存到: {output_file}")# 为每个版本创建新的xlsx文件create_new_xlsx_files(temp_dir, output_base_dir)finally:# 清理临时文件if os.path.exists(temp_dir):shutil.rmtree(temp_dir)def create_new_xlsx_files(temp_dir, output_base_dir):"""为每个版本创建新的xlsx文件"""for version in range(3):# 创建版本特定的临时目录version_temp_dir = os.path.join(output_base_dir, f"temp_version_{version}")if os.path.exists(version_temp_dir):shutil.rmtree(version_temp_dir)shutil.copytree(temp_dir, version_temp_dir)# 替换sheet1.xml文件modified_sheet_path = os.path.join(output_base_dir, str(version), "sheet1.xml")target_sheet_path = find_sheet1_in_dir(version_temp_dir)if target_sheet_path and os.path.exists(modified_sheet_path):# 备份原始文件#backup_path = target_sheet_path + ".backup"#shutil.copy2(target_sheet_path, backup_path)# 替换为修改后的文件shutil.copy2(modified_sheet_path, target_sheet_path)print(f"版本 {version}: 已替换 {target_sheet_path}")# 创建新的xlsx文件output_xlsx = os.path.join(output_base_dir, f"wps{version}.xlsx")create_zip_from_directory(version_temp_dir, output_xlsx)print(f"版本 {version}: 已创建 {output_xlsx}")# 清理临时目录shutil.rmtree(version_temp_dir)def find_sheet1_in_dir(directory):"""在目录中查找sheet1.xml文件"""for root, dirs, files in os.walk(directory):for file in files:if file == "sheet1.xml":return os.path.join(root, file)return Nonedef create_zip_from_directory(directory, output_zip):"""将目录内容压缩为xlsx文件"""# 确保输出文件不存在if os.path.exists(output_zip):os.remove(output_zip)# 创建zip文件with zipfile.ZipFile(output_zip, 'w', zipfile.ZIP_DEFLATED) as zipf: # , compresslevel=6for root, dirs, files in os.walk(directory):for file in files:file_path = os.path.join(root, file)# 计算在zip中的相对路径arcname = os.path.relpath(file_path, directory)zipf.write(file_path, arcname)def indent(elem, level=0):"""美化XML格式,添加缩进"""i = "\n" + level * "  "if len(elem):if not elem.text or not elem.text.strip():elem.text = i + "  "if not elem.tail or not elem.tail.strip():elem.tail = ifor child in elem:indent(child, level + 1)if not elem.tail or not elem.tail.strip():elem.tail = ielse:if level and (not elem.tail or not elem.tail.strip()):elem.tail = idef main():# 使用示例input_file = "4/wps_h0.xlsx"  # 替换为你的xlsx文件路径output_dir = "4"      # 输出目录# 确保输出目录存在os.makedirs(output_dir, exist_ok=True)process_sheet_xml(input_file, output_dir)print("处理完成!")print(f"生成的文件:")print(f"  wps0.xlsx - 无span, 无row的r, 无col的r")print(f"  wps1.xlsx - 有span, 无row的r, 无col的r")  print(f"  wps2.xlsx - 有span, 有row的r, 无col的r")print(f"文件保存在: {os.path.abspath(output_dir)}")if __name__ == "__main__":main()

执行情况如下


python3 stripxml3.py 4/wps_h0.xlsx 4
版本 0 的sheet1.xml已保存到: 4/0/sheet1.xml
版本 1 的sheet1.xml已保存到: 4/1/sheet1.xml
版本 2 的sheet1.xml已保存到: 4/2/sheet1.xml
版本 0: 已替换 4/temp_version_0/xl/worksheets/sheet1.xml
版本 0: 已创建 4/wps0.xlsx
版本 1: 已替换 4/temp_version_1/xl/worksheets/sheet1.xml
版本 1: 已创建 4/wps1.xlsx
版本 2: 已替换 4/temp_version_2/xl/worksheets/sheet1.xml
版本 2: 已创建 4/wps2.xlsx
处理完成!
生成的文件:wps0.xlsx - 无span, 无row的r, 无col的rwps1.xlsx - 有span, 无row的r, 无col的rwps2.xlsx - 有span, 有row的r, 无col的r
文件保存在: /par/4ls -l 4/wps*xlsx
-rw-r--r-- 1 root root 6839896 Aug 21 11:10 4/wps0.xlsx
-rw-r--r-- 1 root root 6839896 Aug 21 11:10 4/wps1.xlsx
-rw-r--r-- 1 root root 6854333 Aug 21 11:10 4/wps2.xlsx
-rw-r--r-- 1 root root 9315700 Aug 21 10:28 4/wps_h0.xlsx

程序功能正确,但处理大文件太耗内存,我处理一个4万行256列的数据,内存不足,使用了交换文件,还是无法完成。于是继续提示:

请把它改成用正则表达式替换,只处理和标签左侧部分,改写后写入xml, 其余的标签按原文件复制,用一个64KB缓冲区边读边写,不全部存在内存。

他给出的程序如下

import os
import re
import zipfile
import shutil
from pathlib import Pathdef process_sheet_xml(input_xlsx_path, output_base_dir):"""使用正则表达式和流式处理处理xlsx文件中的sheet1.xml"""# 创建输出目录for i in range(3):os.makedirs(os.path.join(output_base_dir, str(i)), exist_ok=True)# 临时解压目录temp_dir = "temp_extract"os.makedirs(temp_dir, exist_ok=True)try:# 解压xlsx文件with zipfile.ZipFile(input_xlsx_path, 'r') as zip_ref:zip_ref.extractall(temp_dir)# 查找sheet1.xml文件sheet_path = find_sheet1_in_dir(temp_dir)if not sheet_path:print("未找到sheet1.xml文件")return# 使用正则表达式处理三个版本process_with_regex(sheet_path, output_base_dir)# 为每个版本创建新的xlsx文件create_new_xlsx_files(temp_dir, output_base_dir)finally:# 清理临时文件if os.path.exists(temp_dir):shutil.rmtree(temp_dir)def process_with_regex(sheet_path, output_base_dir):"""使用正则表达式处理sheet1.xml文件"""# 定义正则表达式模式row_pattern = re.compile(r'<row\s+([^>]*)>')cell_pattern = re.compile(r'<c\s+([^>]*)>')# 输出文件路径output_files = [os.path.join(output_base_dir, "0", "sheet1.xml"),os.path.join(output_base_dir, "1", "sheet1.xml"),os.path.join(output_base_dir, "2", "sheet1.xml")]# 缓冲区大小buffer_size = 65536  # 64KB# 处理三个版本for version, output_file in enumerate(output_files):process_single_version(sheet_path, output_file, version, row_pattern, cell_pattern, buffer_size)print(f"版本 {version} 已处理完成: {output_file}")def process_single_version(input_path, output_path, version, row_pattern, cell_pattern, buffer_size):"""处理单个版本的sheet1.xml"""with open(input_path, 'r', encoding='utf-8') as infile, \open(output_path, 'w', encoding='utf-8') as outfile:buffer = []while True:# 读取一块数据chunk = infile.read(buffer_size)if not chunk:breakbuffer.append(chunk)current_text = ''.join(buffer)# 处理当前文本块processed_text = process_text_chunk(current_text, version, row_pattern, cell_pattern)# 写入处理后的文本outfile.write(processed_text)# 清空缓冲区,保留最后部分以避免截断标签buffer = [current_text[-100:]]  # 保留最后100字符避免标签截断# 处理最后剩余的部分if buffer:final_text = ''.join(buffer)processed_final = process_text_chunk(final_text, version, row_pattern, cell_pattern)outfile.write(processed_final)def process_text_chunk(text, version, row_pattern, cell_pattern):"""处理文本块中的row和cell标签"""# 处理row标签def process_row(match):attrs = match.group(1)if version == 0:# 版本0: 移除所有属性return '<row>'elif version == 1:# 版本1: 只保留spans属性spans_match = re.search(r'spans="[^"]*"', attrs)if spans_match:return f'<row {spans_match.group(0)}>'else:return '<row>'else:  # version == 2# 版本2: 保留spans和r属性spans_match = re.search(r'spans="[^"]*"', attrs)r_match = re.search(r'r="\d+"', attrs)kept_attrs = []if spans_match:kept_attrs.append(spans_match.group(0))if r_match:kept_attrs.append(r_match.group(0))if kept_attrs:return f'<row {" ".join(kept_attrs)}>'else:return '<row>'# 处理cell标签def process_cell(match):# 所有版本都移除cell的r属性attrs = match.group(1)# 移除r属性attrs = re.sub(r'r="[^"]*"', '', attrs)attrs = attrs.strip()if attrs:return f'<c {attrs}>'else:return '<c>'# 应用替换text = row_pattern.sub(process_row, text)text = cell_pattern.sub(process_cell, text)return textdef create_new_xlsx_files(temp_dir, output_base_dir):"""为每个版本创建新的xlsx文件"""for version in range(3):# 创建版本特定的临时目录version_temp_dir = os.path.join(output_base_dir, f"temp_version_{version}")if os.path.exists(version_temp_dir):shutil.rmtree(version_temp_dir)shutil.copytree(temp_dir, version_temp_dir)# 替换sheet1.xml文件modified_sheet_path = os.path.join(output_base_dir, str(version), "sheet1.xml")target_sheet_path = find_sheet1_in_dir(version_temp_dir)if target_sheet_path and os.path.exists(modified_sheet_path):# 替换为修改后的文件shutil.copy2(modified_sheet_path, target_sheet_path)print(f"版本 {version}: 已替换 {target_sheet_path}")# 创建新的xlsx文件output_xlsx = os.path.join(output_base_dir, f"wps{version}.xlsx")create_zip_from_directory(version_temp_dir, output_xlsx)print(f"版本 {version}: 已创建 {output_xlsx}")# 清理临时目录shutil.rmtree(version_temp_dir)def find_sheet1_in_dir(directory):"""在目录中查找sheet1.xml文件"""for root, dirs, files in os.walk(directory):for file in files:if file == "sheet1.xml":return os.path.join(root, file)return Nonedef create_zip_from_directory(directory, output_zip):"""将目录内容压缩为xlsx文件"""# 确保输出文件不存在if os.path.exists(output_zip):os.remove(output_zip)# 创建zip文件with zipfile.ZipFile(output_zip, 'w', zipfile.ZIP_DEFLATED) as zipf:for root, dirs, files in os.walk(directory):for file in files:file_path = os.path.join(root, file)# 计算在zip中的相对路径arcname = os.path.relpath(file_path, directory)zipf.write(file_path, arcname)def main():# 使用示例input_file = "4/wps_h0.xlsx"  # 替换为你的xlsx文件路径output_dir = "4"      # 输出目录# 确保输出目录存在os.makedirs(output_dir, exist_ok=True)process_sheet_xml(input_file, output_dir)print("处理完成!")print(f"生成的文件:")print(f"  wps0.xlsx - 无span, 无row的r, 无col的r")print(f"  wps1.xlsx - 有span, 无row的r, 无col的r")  print(f"  wps2.xlsx - 有span, 有row的r, 无col的r")print(f"文件保存在: {os.path.abspath(output_dir)}")if __name__ == "__main__":main()

这个正则版本不知为何处理小文件正确,大文件就格式错误,本来是大文件想用它,只好放弃。
这也说明,市面上的第三方处理xlsx程序为什么大都是读写分离的,比如calamine只读,libxlsxwrite只写,因为像Excel和WPS那样读写兼顾真的要复杂很多。

http://www.xdnf.cn/news/18536.html

相关文章:

  • 服务器间大文件迁移
  • 领域专用AI模型训练指南:医疗、法律、金融三大垂直领域微调效果对比
  • 电商项目_微服务_架构
  • 2025年国内AI大模型现状浅析
  • Shell 脚本条件测试
  • 一款更适合 SpringBoot 的API文档新选择(Spring Boot 应用 API 文档)
  • Rancher 管理的 K8S 集群中部署常见应用(MySQL、Redis、RabbitMQ)并支持扩缩容的操作
  • SpringBoot4发布!新特性解析
  • 2025.8.21总结
  • 【Bug】CentOS 7 使用vim命令报错vim: command not found
  • 37、需求预测与库存优化 (快消品) - /供应链管理组件/fmcg-inventory-optimization
  • AP状态管理中提到的两种“业务逻辑”
  • Java实现一个简单的LRU缓存对象
  • 50 C++ STL模板库-算法库 algorithm
  • python的校园研招网系统
  • RHCA10NUMA
  • Pytorch框架学习
  • Git 新手完全指南(一):从零开始掌握版本控制
  • 59. 螺旋矩阵 II|从“左闭右开”的圈层模拟入手(附图解与 C++ 实现)
  • 在 Linux 和 Docker 中部署 MinIO 对象存储
  • 使用Spring Retry组件优雅地实现重试
  • 【Python】利用heapq 模块实现一个按优先级排序的队列
  • 数字化图书管理系统设计实践(java)
  • CorrectNav——基于VLM构建带“自我纠正飞轮”的VLN:通过「视觉输入和语言指令」预测导航动作,且从动作和感知层面生成自我修正数据
  • 学习嵌入式的第二十二天——数据结构——双向链表
  • 永磁同步电机谐波抑制算法(13)——传统预测控制与传统谐波抑制的碰撞
  • week2-[二维数组]排队
  • MySQL 50 道经典练习题及答案
  • Java毕业设计选题推荐 |基于SpringBoot+Vue的知识产权管理系统设计与实现
  • Effective C++ 条款52:写了placement new也要写placement delete