计算sim.log 的各个点的时间

本文介绍了一种Python脚本,用于解析特定的日志文件,并通过正则表达式提取并分类关键事件,如开始、警告、验证、提交和完成。脚本详细展示了如何根据日志中的关键词进行事件识别和输出。


#!/usr/bin/python
import sys, re

file=open('/storage/sim/log/update/sim.log','r')
begin_flag=cpw_flag=vs_flag=0
resume_flag=commit_flag=end_flag=0

for line in file:
    if(re.search("BEGINNING SIM PROCEDURE+",line)):
        begin_flag+=1
        print line
        print "%s BEGINNING Patch:%s"%(begin_flag,line[0:17])
    elif(re.search("CP_W+", line)):
        cpw_flag+=1
        print "%s CP_WARNING:%s"%(cpw_flag,line[0:17])
    elif(re.search("VERIFY_S+", line)):
        vs_flag+=1
        print "%s VERIFY_SOFTWARE:%s"%(vs_flag,line[0:17])
    elif(re.search("--action commit+",line)):
        commit_flag+=1
        print "%s COMMIT:%s"%(commit_flag,line[0:17])

    elif(re.search("COMPLETED SIM PROCEDURE+",line)):
        end_flag+=1
        print "%s COMPLETED:%s"%(end_flag,line[0:17])
        begin_flag=cpw_flag=vs_flag=0
        resume_flag=commit_flag=end_flag=0
        print '\n'
    elif(re.search("RESUMING SIM PROCEDURE+",line)):
        resume_flag+=1
        if(cpw_flag!=0 and vs_flag==0):
            print "resume:%s"%(line[0:17])
            resume_flag=0
        elif(vs_flag!=0 and commit_flag==0 and resume_flag==1):
            print "resume:%s"%(line[0:17])
            resume_flag=0
        elif(commit_flag==1 and resume_flag==1):
            print "commit_begin:%s"%(line[0:17])
            resume_flag=0
            commit_flag=0

if __name__ == '__main__':
    pass




import os import tempfile import pythoncom import win32com.client import threading import shutil import tkinter as tk from tkinter import filedialog, ttk, messagebox, scrolledtext from docx import Document from PyPDF2 import PdfMerger, PdfReader, PdfWriter from reportlab.pdfgen import canvas from reportlab.lib.pagesizes import letter from reportlab.pdfbase import pdfmetrics from reportlab.pdfbase.ttfonts import TTFont from reportlab.lib.colors import red, black, white from reportlab.platypus import Table, TableStyle from io import BytesIO from datetime import datetime import wx from collections import defaultdict class PDFConverterApp: def __init__(self, root): self.root = root self.root.title("audio_data") self.root.geometry("800x650") self.folders = [] self.log_messages = [] self.output_path = "" self.backup_mode = tk.BooleanVar(value=True) self.point_22_mode = tk.BooleanVar(value=False) self.rename_mode = tk.BooleanVar(value=True) self.output_filename = tk.StringVar(value="听筒磁干扰_Simulation_Result") self.create_widgets() def create_widgets(self): top_frame = ttk.Frame(self.root, padding=10) # 修正:使用 Frame top_frame.pack(fill=tk.X) output_frame = ttk.LabelFrame(self.root, text="输出设置", padding=10) # 修正:使用 LabelFrame output_frame.pack(fill=tk.X, padx=10, pady=(0, 5)) ttk.Label(output_frame, text="文件名:").grid(row=0, column=0, sticky=tk.W, padx=(0, 5)) filename_entry = ttk.Entry(output_frame, textvariable=self.output_filename, width=30) filename_entry.grid(row=0, column=1, sticky=tk.W, padx=5) ttk.Label(output_frame, text="输出路径:").grid(row=0, column=2, sticky=tk.W, padx=(20, 5)) self.path_entry = ttk.Entry(output_frame, width=40, state='readonly') self.path_entry.grid(row=0, column=3, sticky=tk.EW, padx=5) browse_btn = ttk.Button(output_frame, text="浏览...", command=self.choose_output_path) browse_btn.grid(row=0, column=4, padx=(5, 0)) output_frame.columnconfigure(3, weight=1) check_frame = ttk.Frame(output_frame) # 修正:使用 Frame check_frame.grid(row=1, column=0, columnspan=5, sticky=tk.W, padx=0, pady=5) self.point_22_check = ttk.Checkbutton( check_frame, text="2号位", variable=self.point_22_mode ) self.point_22_check.pack(side=tk.LEFT, padx=(0, 15)) self.backup_check = ttk.Checkbutton( check_frame, text="报告存档", variable=self.backup_mode ) self.backup_check.pack(side=tk.LEFT, padx=(0, 15)) self.rename_check = ttk.Checkbutton( check_frame, text="启用重命名", variable=self.rename_mode ) self.rename_check.pack(side=tk.LEFT) add_btn = ttk.Button(top_frame, text="添加文件夹", command=self.add_folder) add_btn.pack(side=tk.LEFT, padx=5) remove_btn = ttk.Button(top_frame, text="移除选中", command=self.remove_selected) remove_btn.pack(side=tk.LEFT, padx=5) clear_btn = ttk.Button(top_frame, text="清空列表", command=self.clear_list) clear_btn.pack(side=tk.LEFT, padx=5) process_btn = ttk.Button(top_frame, text="开始处理", command=self.start_processing) process_btn.pack(side=tk.RIGHT, padx=5) list_frame = ttk.LabelFrame(self.root, text="待处理文件夹", padding=10) # 修正:使用 LabelFrame list_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=5) scrollbar = ttk.Scrollbar(list_frame) scrollbar.pack(side=tk.RIGHT, fill=tk.Y) self.folder_list = tk.Listbox( list_frame, selectmode=tk.EXTENDED, yscrollcommand=scrollbar.set, height=10 ) self.folder_list.pack(fill=tk.BOTH, expand=True) scrollbar.config(command=self.folder_list.yview) log_frame = ttk.LabelFrame(self.root, text="处理日志", padding=10) # 修正:使用 LabelFrame log_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=5) self.log_text = scrolledtext.ScrolledText( log_frame, wrap=tk.WORD, state=tk.DISABLED ) self.log_text.pack(fill=tk.BOTH, expand=True) self.progress = ttk.Progressbar( self.root, orient=tk.HORIZONTAL, mode='determinate' ) self.progress.pack(fill=tk.X, padx=10, pady=5) # 后续方法保持不变... def choose_output_path(self): path = filedialog.askdirectory(title="选择输出文件夹") if path: self.output_path = path self.path_entry.config(state='normal') self.path_entry.delete(0, tk.END) self.path_entry.insert(0, path) self.path_entry.config(state='readonly') self.log(f"已设置输出路径: {path}") def apply_rename_rule(self, original_files): """应用重命名规则:使用文件夹名称作为文件名(删除最后一个横杠及其后内容)""" renamed_files = [] folder_file_counts = defaultdict(int) # 记录每个文件夹下的文件数量 for file_path in original_files: # 获取文件所在文件夹的路径和名称 folder_path = os.path.dirname(file_path) folder_name = os.path.basename(folder_path) # +++ 新增处理逻辑:删除最后一个横杠及其后内容 +++ if '-' in folder_name: # 找到最后一个横杠的位置 dash_index = folder_name.rfind('-') # 删除横杠及其后所有字符 folder_name = folder_name[:dash_index] self.log(f"已处理文件夹名: {os.path.basename(folder_path)} → {folder_name}") # 获取文件扩展名 _, ext = os.path.splitext(file_path) # 更新文件夹文件计数器 file_count = folder_file_counts[folder_path] + 1 folder_file_counts[folder_path] = file_count # 生成新文件名:文件夹名称 + 序号(如果多于一个文件) if file_count == 1: new_name = f"{folder_name}{ext}" # 单文件不加序号 else: new_name = f"{folder_name}_{file_count}{ext}" # 多文件加序号 new_path = os.path.join(folder_path, new_name) # 确保新文件名不冲突 counter = 1 while os.path.exists(new_path): # 如果文件名冲突,添加后缀序号 new_name = f"{folder_name}_{file_count}_{counter}{ext}" new_path = os.path.join(folder_path, new_name) counter += 1 # 执行重命名 try: os.rename(file_path, new_path) self.log(f"已将 '{os.path.basename(file_path)}' 重命名为 '{new_name}'") renamed_files.append(new_path) except Exception as e: self.log(f"重命名失败: {str(e)}") renamed_files.append(file_path) # 保留原文件路径 return renamed_files def add_folder(self): """添加要处理的文件夹""" folders = filedialog.askdirectory( title="选择要处理的文件夹", mustexist=True ) if folders: self.folders.append(folders) self.folder_list.insert(tk.END, folders) self.log(f"已添加文件夹: {folders}") def remove_selected(self): """移除选中的文件夹""" selected = self.folder_list.curselection() for index in selected[::-1]: folder = self.folder_list.get(index) self.folder_list.delete(index) self.folders.remove(folder) self.log(f"已移除文件夹: {folder}") def clear_list(self): """清空文件夹列表""" self.folder_list.delete(0, tk.END) self.folders = [] self.log("已清空文件夹列表") def log(self, message): """向日志区域添加消息""" timestamp = datetime.now().strftime("%H:%M:%S") log_entry = f"[{timestamp}] {message}" self.log_messages.append(log_entry) self.log_text.config(state=tk.NORMAL) self.log_text.insert(tk.END, log_entry + "\n") self.log_text.config(state=tk.DISABLED) self.log_text.yview(tk.END) # 自动滚动到底部 self.root.update_idletasks() def start_processing(self): """启动处理过程""" if not self.folders: messagebox.showwarning("警告", "请先添加要处理的文件夹") return # 禁用处理按钮 self.root.title("Word 转 PDF 合并工具 - 处理中...") self.progress["value"] = 0 # 在新线程中处理,避免界面冻结 thread = threading.Thread(target=self.process_folders) thread.daemon = True thread.start() # +++ 修改方法:备份时获取校准数据 +++ def backup_data_files(self, folder_path, backup_dir): """递归查找并备份所有.xlsx和.csv文件""" self.log(f"开始在文件夹中搜索所有Excel和CSV文件: {folder_path}") backup_count = 0 try: self.log(f"开始备份数据文件: {folder_path}") backup_count = 0 # +++ 修复1: 确保备份目录存在 +++ os.makedirs(backup_dir, exist_ok=True) for root, dirs, files in os.walk(folder_path): # +++ 修复2: 保持原始目录结构 +++ rel_path = os.path.relpath(root, folder_path) dest_dir = os.path.join(backup_dir, rel_path) if not os.path.exists(dest_dir): os.makedirs(dest_dir, exist_ok=True) for file in files: if file.lower().endswith(('.xlsx', '.csv')): src = os.path.join(root, file) dst = os.path.join(dest_dir, file) try: # +++ 修复3: 使用copy2保留元数据 +++ shutil.copy2(src, dst) backup_count += 1 self.log(f"✅ 成功备份: {file}") except Exception as e: self.log(f"⚠️ 备份失败: {file} ({str(e)})") self.log(f"完成备份! 共处理 {backup_count} 个文件") return backup_count > 0 except Exception as e: self.log(f"❌ 备份过程出错: {str(e)}") return False def process_folders(self): """处理多个文件夹中的Word文件""" try: # 提前初始化 output_folder if self.output_path: output_folder = self.output_path else: output_folder = next((p for p in self.folders if os.path.isdir(p)), os.getcwd()) self.log(f"开始处理 {len(self.folders)} 个文件夹...") # 获取所有文件夹中的Word文件 word_files = self.get_all_word_files(self.folders) if not word_files: self.log("没有找到任何Word文档") return # +++ 应用重命名规则 +++ if self.rename_mode.get(): self.log("应用重命名规则...") word_files = self.apply_rename_rule(word_files) self.log(f"共找到 {len(word_files)} 个Word文档") self.progress["maximum"] = len(word_files) + 5 # 文件数 + 合并步骤 backup_root = os.path.join(output_folder, "报告存档") if self.backup_mode.get(): os.makedirs(backup_root, exist_ok=True) for idx, folder_path in enumerate(self.folders): backup_dir = os.path.join(backup_root, f"DataBackup_{idx + 1}") self.backup_data_files(folder_path, backup_dir) # 创建临时目录存储转换后的PDF with tempfile.TemporaryDirectory() as temp_dir: pdf_files_with_header = [] toc_entries = [] all_tables = {} current_page = 1 # 处理每个Word文件 for i, word_file in enumerate(word_files): self.progress["value"] = i + 1 file_name = os.path.splitext(os.path.basename(word_file))[0] display_name = file_name # 修改Word文档逻辑 modified_word_path = word_file if self.point_22_mode.get() or "GSM" in file_name.upper(): # 创建临时副本进行修改 temp_word_path = os.path.join(temp_dir, os.path.basename(word_file)) shutil.copy2(word_file, temp_word_path) if self.modify_word_spec(temp_word_path): modified_word_path = temp_word_path original_pdf = os.path.join(temp_dir, f"{file_name}_original.pdf") pdf_with_header = os.path.join(temp_dir, f"{file_name}_with_header.pdf") if self.backup_mode.get(): try: # 为每个Word文件创建备份目录 dest_dir = os.path.join(backup_root, file_name) os.makedirs(dest_dir, exist_ok=True) # 备份Word文件 word_dest = os.path.join(dest_dir, os.path.basename(modified_word_path)) shutil.copy2(modified_word_path, word_dest) self.log(f"Word文件备份成功: {word_file} → {word_dest}") # +++ 备份数据文件并获取校准数据 +++ folder_path = os.path.dirname(word_file) except OSError as e: self.log(f"文件备份失败: {e}") except Exception as e: self.log(f"未知错误: {e}") # 提取表格数据 tables = self.extract_spec_table(modified_word_path) if tables: all_tables[display_name] = tables self.log(f"已从 {display_name} 中提取 {len(tables)} 个数据表格") # 转换为PDF if self.word_to_pdf(modified_word_path, original_pdf): # 添加内联标题 if self.add_inline_header(original_pdf, display_name, pdf_with_header): pdf_files_with_header.append(pdf_with_header) toc_entries.append((display_name, current_page)) current_page += self.get_pdf_page_count(pdf_with_header) else: pdf_files_with_header.append(original_pdf) toc_entries.append((display_name, current_page)) current_page += self.get_pdf_page_count(original_pdf) else: self.log(f"跳过 {display_name},转换失败") # 更新进度条 self.progress["value"] = len(word_files) + 1 if not pdf_files_with_header: self.log("没有成功转换的PDF文件,无法进行合并") return # 获取输出路径 if self.output_path: output_folder = self.output_path else: output_folder = next((p for p in self.folders if os.path.isdir(p)), os.getcwd()) # 获取文件名 report_name = self.output_filename.get().strip() if not report_name: report_name = self.get_folder_name_parts(self.folders[0]) # 使用默认规则 output_pdf = os.path.join(output_folder, f"{report_name}.pdf") # 合并PDF success = self.merge_pdfs_with_summary( pdf_files_with_header, toc_entries, all_tables, output_pdf ) self.progress["value"] = len(word_files) + 3 if success: self.log(f"处理完成!输出文件: {output_pdf}") messagebox.showinfo("完成", f"处理完成!输出文件: {output_pdf}") else: self.log("处理失败") messagebox.showerror("错误", "处理过程中出现错误") self.root.title("Word 转 PDF 合并工具") except Exception as e: self.log(f"处理过程中出现错误: {str(e)}") messagebox.showerror("错误", f"处理过程中出现错误: {str(e)}") self.root.title("Word 转 PDF 合并工具") # 以下是原有的处理函数,保持不变但添加为类方法 def extract_spec_table(self, word_path): """从Word文档中提取SPEC(dB)、Simulation和Pass/Fail数据表格""" try: doc = Document(word_path) tables = [] for table in doc.tables: headers = [cell.text.strip() for cell in table.rows[0].cells] if "SPEC(dB)" in headers and "Simulation" in headers and "Pass/Fail" in headers: table_data = [] table_data.append(headers) for row in table.rows[1:]: row_data = [cell.text.strip() for cell in row.cells] table_data.append(row_data) tables.append(table_data) return tables except Exception as e: self.log(f"提取 {os.path.basename(word_path)} 中的表格时出错: {str(e)}") return [] def modify_word_spec(self, word_path): try: doc = Document(word_path) filename = os.path.basename(word_path).upper() has_gsm = "GSM" in filename # 移动到try块内部 # 确定SPEC基准值 if self.point_22_mode.get(): # 默认22号位 spec_value = 20 if has_gsm else 18 else: # 2号位未启用 spec_value = 22 if has_gsm else 20 modified = False # 初始化修改标志 # 遍历文档所有表格 for table in doc.tables: headers = [cell.text.strip() for cell in table.rows[0].cells] try: spec_index = headers.index("SPEC(dB)") # 定位SPEC列 sim_index = headers.index("Simulation") # 定位Simulation列 pf_index = headers.index("Pass/Fail") # 定位Pass/Fail列 except ValueError: continue # 跳过不含目标列的表 # 标记已找到可修改表格 modified = True # 修改每行数据 for row in table.rows[1:]: cells = row.cells # 更新SPEC值 if spec_index < len(cells): cells[spec_index].text = str(spec_value) # 更新Pass/Fail状态 if sim_index < len(cells) and pf_index < len(cells): try: sim_value = float(cells[sim_index].text) new_status = "PASS" if sim_value < spec_value else "FAIL" cells[pf_index].text = new_status except ValueError: pass # 忽略格式错误 # 保存修改后的文档 if modified: doc.save(word_path) self.log(f"已修改 {os.path.basename(word_path)} 的SPEC值为{spec_value}") return modified except Exception as e: self.log(f"修改 {os.path.basename(word_path)} 失败: {str(e)}") return False def add_inline_header(self, pdf_path, title, output_path): """在PDF的第一页顶部添加一行红色加粗的标题""" try: reader = PdfReader(pdf_path) writer = PdfWriter() if len(reader.pages) > 0: first_page = reader.pages[0] packet = BytesIO() can = canvas.Canvas(packet, pagesize=letter) width, height = letter font_name = "Helvetica-Bold" try: pdfmetrics.registerFont(TTFont('SimSun', 'simsun.ttc')) pdfmetrics.registerFont(TTFont('SimSun-Bold', 'simsun.ttc')) font_name = "SimSun-Bold" except: pass can.setFont(font_name, 14) can.setFillColor(red) can.drawString(50, height - 50, title) can.save() packet.seek(0) title_reader = PdfReader(packet) title_page = title_reader.pages[0] first_page.merge_page(title_page) writer.add_page(first_page) for page in reader.pages[1:]: writer.add_page(page) with open(output_path, "wb") as f: writer.write(f) return True return False except Exception as e: self.log(f"PDF添加标题失败: {str(e)}") return False # +++ 修改方法:创建Summary页(核心修改) +++ def create_summary_page(self, toc_entries, all_tables, output_path): """创建包含三列数据的Summary页(无Calibration列)""" try: c = canvas.Canvas(output_path, pagesize=letter) width, height = letter font_name = "Helvetica" try: pdfmetrics.registerFont(TTFont('SimSun', 'simsun.ttc')) font_name = "SimSun" except: pass # Summary标题 c.setFont(font_name, 24) c.setFillColor(red) c.drawCentredString(width / 2.0, height - 50, "Summary") c.setFillColor(black) y_position = height - 100 # 添加数据汇总表格 if all_tables: c.setFont(font_name, 16) c.drawString(50, y_position, "Data Summary:") y_position -= 30 c.setFont(font_name, 10) table_width = width - 100 for doc_name, tables in all_tables.items(): c.setFont(font_name, 12) c.setFillColor(red) c.drawString(60, y_position, f"Document: {doc_name}") y_position -= 20 c.setFillColor(black) c.setFont(font_name, 10) # 处理每个表格 for table_data in tables: # 确保表格有数据行 if len(table_data) < 2: # 至少包含表头+1行数据 continue # 表头格式(三列) headers = ["SPEC(dB)", "Simulation", "Pass/Fail"] # 提取第一行原始数据(跳过表头) data_row = table_data[1] if len(table_data) > 1 else ["N/A"] * 3 # 确保数据行有足够列 while len(data_row) < 3: data_row.append("N/A") # 创建数据行:三列 new_row = [ data_row[0], # SPEC(dB)值 data_row[1], # Simulation值 data_row[2], # Pass/Fail值 ] # 表格数据:表头+数据行 modified_table = [headers, new_row] # 设置三列等宽布局 col_widths = [table_width / 3] * 3 table = Table(modified_table, colWidths=col_widths) # 设置表格样式 style = TableStyle([ ('BACKGROUND', (0, 0), (-1, 0), white), ('TEXTCOLOR', (0, 0), (-1, 0), black), ('ALIGN', (0, 0), (-1, -1), 'CENTER'), ('FONTNAME', (0, 0), (-1, 0), font_name), ('FONTNAME', (0, 1), (-1, -1), font_name), ('BOTTOMPADDING', (0, 0), (-1, 0), 12), ('BACKGROUND', (0, 1), (-1, -1), white), ('GRID', (0, 0), (-1, -1), 1, black) ]) table.setStyle(style) # 计算表格高度并绘制 table_height = table.wrap(0, 0)[1] if y_position - table_height < 50: c.showPage() y_position = height - 50 c.setFont(font_name, 24) c.setFillColor(red) c.drawCentredString(width / 2.0, y_position, "Summary") y_position -= 50 c.setFillColor(black) table.drawOn(c, 50, y_position - table_height) y_position -= (table_height + 20) c.save() return output_path except Exception as e: self.log(f"创建Summary页失败: {str(e)}") return None def word_to_pdf(self, word_path, pdf_path): """将Word文档转换为PDF""" pythoncom.CoInitialize() try: word = win32com.client.Dispatch("Word.Application") word.Visible = False doc = word.Documents.Open(os.path.abspath(word_path)) doc.SaveAs(os.path.abspath(pdf_path), FileFormat=17) doc.Close() word.Quit() self.log(f"已将 {os.path.basename(word_path)} 转换为PDF") return True except Exception as e: self.log(f"转换 {os.path.basename(word_path)} 时出错: {str(e)}") return False finally: pythoncom.CoUninitialize() def get_pdf_page_count(self, pdf_path): """获取PDF文件的页数""" try: reader = PdfReader(pdf_path) return len(reader.pages) except: return 0 def merge_pdfs_with_summary(self, pdf_files, toc_entries, all_tables, output_path): """合并PDF文件并添加Summary页""" try: with tempfile.NamedTemporaryFile(delete=False, suffix='.pdf') as summary_file: summary_path = summary_file.name # 调用修改后的create_summary_page,传入三个参数 self.create_summary_page(toc_entries, all_tables, summary_path) summary_page_count = self.get_pdf_page_count(summary_path) updated_toc_entries = [(title, page_num + summary_page_count) for title, page_num in toc_entries] merger = PdfMerger() merger.append(summary_path) current_page = summary_page_count for pdf, (title, _) in zip(pdf_files, updated_toc_entries): merger.append(pdf) merger.add_outline_item(title, current_page) current_page += self.get_pdf_page_count(pdf) merger.write(output_path) merger.close() os.remove(summary_path) self.log(f"已成功合并 {len(pdf_files)} 个PDF文件") return True except Exception as e: self.log(f"合并PDF时出错: {str(e)}") return False def get_all_word_files(self, folder_paths): """获取所有Word文件""" word_extensions = ['.docx', '.doc'] word_files = [] for folder_path in folder_paths: if not os.path.isdir(folder_path): continue for file in os.listdir(folder_path): file_ext = os.path.splitext(file)[1].lower() if file_ext in word_extensions: word_path = os.path.join(folder_path, file) word_files.append(word_path) return word_files def get_folder_name_parts(self, folder_paths): """生成报告文件名""" if not folder_paths: return "听筒磁干扰仿真报告" folder_path = folder_paths[0] norm_path = os.path.normpath(folder_path) parts = [p for p in norm_path.split(os.sep) if p] if len(parts) >= 3: return f"{parts[-3]}_{parts[-2]}_{parts[-1]}" elif len(parts) == 2: return f"{parts[-2]}_{parts[-1]}" elif len(parts) == 1: return parts[0] return "听筒磁干扰仿真报告" if __name__ == "__main__": root = tk.Tk() app = PDFConverterApp(root) root.mainloop() # 添加这行启动事件循环 将这段代码的备份代码按上述结构修改
10-19
import os import tempfile import shutil import threading import tkinter as tk from tkinter import filedialog, ttk, messagebox, scrolledtext from docx import Document from PyPDF2 import PdfMerger, PdfReader, PdfWriter from reportlab.lib.pagesizes import letter, A4 from reportlab.pdfgen import canvas from datetime import datetime import pythoncom import win32com.client from io import BytesIO from reportlab.pdfbase import pdfmetrics from reportlab.pdfbase.ttfonts import TTFont # 修改Table的导入,使用别名RLTable from reportlab.platypus import Table as RLTable, TableStyle from reportlab.lib import colors class Table: pass class PDFConverterApp: def __init__(self, root): self.root = root self.root.title("音频数据处理工具") self.root.geometry("800x650") # 初始化变量 self.folders = [] self.output_path = "" self.backup_mode = tk.BooleanVar(value=True) self.point_mode = tk.BooleanVar(value=False) self.output_filename = tk.StringVar(value="听筒磁干扰_结果报告") # 创建界面 self.create_widgets() def create_widgets(self): """创建GUI界面组件""" # 输出设置区域 output_frame = ttk.LabelFrame(self.root, text="输出设置", padding=10) output_frame.pack(fill=tk.X, padx=10, pady=5) # 文件名设置 ttk.Label(output_frame, text="文件名:").grid(row=0, column=0, sticky=tk.W) ttk.Entry(output_frame, textvariable=self.output_filename, width=30).grid(row=0, column=1, sticky=tk.W, padx=5) # 输出路径选择 ttk.Label(output_frame, text="输出路径:").grid(row=0, column=2, sticky=tk.W, padx=(20, 5)) self.path_entry = ttk.Entry(output_frame, width=40, state='readonly') self.path_entry.grid(row=0, column=3, sticky=tk.EW) ttk.Button(output_frame, text="浏览...", command=self.choose_output_path).grid(row=0, column=4, padx=5) output_frame.columnconfigure(3, weight=1) # 选项区域 options_frame = ttk.Frame(output_frame) options_frame.grid(row=0, column=5, sticky=tk.W, padx=(20, 0)) ttk.Checkbutton(options_frame, text="报告存档", variable=self.backup_mode).pack(side=tk.LEFT) ttk.Checkbutton(options_frame, text="2号位", variable=self.point_mode, padding=(10, 0)).pack(side=tk.LEFT) # 操作按钮区域 btn_frame = ttk.Frame(self.root, padding=10) btn_frame.pack(fill=tk.X) ttk.Button(btn_frame, text="添加文件夹", command=self.add_folder).pack(side=tk.LEFT, padx=5) ttk.Button(btn_frame, text="移除选中", command=self.remove_selected).pack(side=tk.LEFT, padx=5) ttk.Button(btn_frame, text="清空列表", command=self.clear_list).pack(side=tk.LEFT, padx=5) ttk.Button(btn_frame, text="开始处理", command=self.start_processing).pack(side=tk.RIGHT, padx=5) # 文件夹列表区域 list_frame = ttk.LabelFrame(self.root, text="待处理文件夹", padding=10) list_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=5) scrollbar = ttk.Scrollbar(list_frame) scrollbar.pack(side=tk.RIGHT, fill=tk.Y) self.folder_list = tk.Listbox(list_frame, selectmode=tk.EXTENDED, yscrollcommand=scrollbar.set, height=10) self.folder_list.pack(fill=tk.BOTH, expand=True) scrollbar.config(command=self.folder_list.yview) # 日志区域 log_frame = ttk.LabelFrame(self.root, text="处理日志", padding=10) log_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=5) self.log_text = scrolledtext.ScrolledText(log_frame, wrap=tk.WORD, state=tk.DISABLED) self.log_text.pack(fill=tk.BOTH, expand=True) # 进度条 self.progress = ttk.Progressbar(self.root, orient=tk.HORIZONTAL, mode='determinate') self.progress.pack(fill=tk.X, padx=10, pady=5) # === 文件操作相关方法 === def choose_output_path(self): """选择输出文件夹""" path = filedialog.askdirectory(title="选择输出文件夹") if path: self.output_path = path self.path_entry.config(state='normal') self.path_entry.delete(0, tk.END) self.path_entry.insert(0, path) self.path_entry.config(state='readonly') self.log(f"输出路径设置为: {path}") def add_folder(self): """添加要处理的文件夹""" folders = filedialog.askdirectory(title="选择文件夹", mustexist=True) if folders: self.folders.append(folders) self.folder_list.insert(tk.END, folders) self.log(f"已添加文件夹: {folders}") def remove_selected(self): """移除选中的文件夹""" for index in self.folder_list.curselection()[::-1]: folder = self.folder_list.get(index) self.folder_list.delete(index) self.folders.remove(folder) self.log(f"已移除文件夹: {folder}") def clear_list(self): """清空文件夹列表""" self.folder_list.delete(0, tk.END) self.folders = [] self.log("已清空文件夹列表") def log(self, message): """记录日志消息""" timestamp = datetime.now().strftime("%H:%M:%S") log_entry = f"[{timestamp}] {message}" self.log_text.config(state=tk.NORMAL) self.log_text.insert(tk.END, log_entry + "\n") self.log_text.config(state=tk.DISABLED) self.log_text.yview(tk.END) self.root.update_idletasks() # === 核心处理功能 === def start_processing(self): """启动处理流程""" if not self.folders: messagebox.showwarning("警告", "请先添加要处理的文件夹") return self.root.title("音频数据处理 - 处理中...") self.progress["value"] = 0 thread = threading.Thread(target=self.process_folders) thread.daemon = True thread.start() def process_folders(self): """处理所有文件夹中的文件""" try: # 收集所有Word文件 word_files = self.get_word_files() if not word_files: self.log("未找到任何Word文档") return self.progress["maximum"] = len(word_files) + 5 # 设置输出路径 output_folder = self.output_path or self.folders[0] backup_root = os.path.join(output_folder, "报告存档") with tempfile.TemporaryDirectory() as temp_dir: pdf_files = [] toc_entries = [] all_tables = {} current_page = 1 # 处理每个Word文件 for i, word_file in enumerate(word_files): self.progress["value"] = i + 1 display_name = os.path.splitext(os.path.basename(word_file))[0] # 备份处理 if self.backup_mode.get(): self.backup_files(word_file, backup_root) # 修改Word文档 modified_path = self.modify_word(word_file, temp_dir) # 提取表格数据 tables = self.extract_tables(modified_path) if tables: all_tables[display_name] = tables # 转换为PDF pdf_path = self.convert_to_pdf(modified_path, temp_dir, display_name) if pdf_path: pdf_files.append(pdf_path) toc_entries.append((display_name, current_page)) current_page += self.get_page_count(pdf_path) # 合并PDF if pdf_files: report_name = self.output_filename.get().strip() or "结果报告" output_pdf = os.path.join(output_folder, f"{report_name}.pdf") if self.merge_pdfs(pdf_files, toc_entries, all_tables, output_pdf): self.log(f"处理完成!输出文件: {output_pdf}") messagebox.showinfo("完成", f"处理完成!输出文件: {output_pdf}") self.root.title("音频数据处理") except Exception as e: self.log(f"处理出错: {str(e)}") messagebox.showerror("错误", f"处理出错: {str(e)}") self.root.title("音频数据处理") def get_word_files(self): """获取所有Word文件路径""" word_files = [] for folder in self.folders: for file in os.listdir(folder): if file.lower().endswith(('.docx', '.doc')): word_files.append(os.path.join(folder, file)) return word_files def backup_files(self, word_path, backup_root): """备份文件到指定目录""" try: file_name = os.path.splitext(os.path.basename(word_path))[0] backup_dir = os.path.join(backup_root, file_name) os.makedirs(backup_dir, exist_ok=True) # 备份Word文件 shutil.copy2(word_path, os.path.join(backup_dir, os.path.basename(word_path))) self.log(f"已备份Word文件: {file_name}") except Exception as e: self.log(f"备份失败: {str(e)}") def modify_word(self, word_path, temp_dir): """修改Word文档内容""" try: doc = Document(word_path) modified = False # 确定SPEC基准值 spec_value = 22 if ("GSM" in word_path.upper() and self.point_mode.get()) else 20 # 修改表格内容 for table in doc.tables: headers = [cell.text.strip() for cell in table.rows[0].cells] if "SPEC(dB)" in headers and "Simulation" in headers and "Pass/Fail" in headers: # 查找列索引 spec_idx = headers.index("SPEC(dB)") sim_idx = headers.index("Simulation") pf_idx = headers.index("Pass/Fail") # 修改每行数据 for row in table.rows[1:]: # 更新SPEC值 row.cells[spec_idx].text = str(spec_value) # 更新Pass/Fail状态 try: sim_val = float(row.cells[sim_idx].text) row.cells[pf_idx].text = "PASS" if sim_val < spec_value else "FAIL" except ValueError: pass # 设置单元格居中 for cell in row.cells: for paragraph in cell.paragraphs: paragraph.alignment = 1 # 居中 modified = True if modified: temp_path = os.path.join(temp_dir, os.path.basename(word_path)) doc.save(temp_path) return temp_path return word_path except Exception as e: self.log(f"修改Word失败: {str(e)}") return word_path def extract_tables(self, word_path): """从Word文档中提取表格数据""" try: doc = Document(word_path) tables = [] for table in doc.tables: headers = [cell.text.strip() for cell in table.rows[0].cells] if "SPEC(dB)" in headers and "Simulation" in headers and "Pass/Fail" in headers: table_data = [headers] for row in table.rows[1:]: table_data.append([cell.text.strip() for cell in row.cells]) tables.append(table_data) return tables except Exception as e: self.log(f"提取表格失败: {str(e)}") return [] def convert_to_pdf(self, word_path, temp_dir, title): """将Word转换为PDF并添加标题""" try: # 转换为PDF pdf_path = os.path.join(temp_dir, f"{os.path.basename(word_path)}.pdf") self.word_to_pdf(word_path, pdf_path) # 添加标题 titled_pdf = os.path.join(temp_dir, f"titled_{os.path.basename(pdf_path)}") self.add_pdf_title(pdf_path, title, titled_pdf) return titled_pdf except Exception as e: self.log(f"转换失败: {str(e)}") return None def word_to_pdf(self, word_path, pdf_path): """使用Word COM接口转换为PDF""" pythoncom.CoInitialize() try: word = win32com.client.Dispatch("Word.Application") word.Visible = False doc = word.Documents.Open(os.path.abspath(word_path)) doc.SaveAs(os.path.abspath(pdf_path), FileFormat=17) doc.Close() word.Quit() self.log(f"已转换: {os.path.basename(word_path)} → PDF") return True except Exception as e: self.log(f"转换失败: {str(e)}") return False finally: pythoncom.CoUninitialize() def add_pdf_title(self, pdf_path, title, output_path): """在PDF首页顶部添加标题""" try: reader = PdfReader(pdf_path) writer = PdfWriter() # 创建标题Canvas packet = BytesIO() c = canvas.Canvas(packet, pagesize=letter) width, height = letter c.setFont("Helvetica-Bold", 14) c.setFillColorRGB(1, 0, 0) # 红色 c.drawString(50, height - 50, title) c.save() # 合并到第一页 packet.seek(0) title_page = PdfReader(packet).pages[0] first_page = reader.pages[0] first_page.merge_page(title_page) writer.add_page(first_page) # 添加剩余页面 for page in reader.pages[1:]: writer.add_page(page) # 保存结果 with open(output_path, "wb") as f: writer.write(f) return True except Exception as e: self.log(f"添加标题失败: {str(e)}") return False def get_page_count(self, pdf_path): """获取PDF页数""" try: return len(PdfReader(pdf_path).pages) except: return 0 def merge_pdfs(self, pdf_files, toc_entries, all_tables, output_path): """合并PDF并添加摘要页(修复空文件问题)""" try: with tempfile.NamedTemporaryFile(delete=False, suffix='.pdf') as summary_file: summary_path = summary_file.name # 创建摘要页并验证 if not self.create_summary_page(all_tables, summary_path): raise Exception("摘要页创建失败") # 验证摘要页文件 if not os.path.exists(summary_path) or os.path.getsize(summary_path) == 0: raise Exception("摘要页是空文件") # 获取摘要页页数 summary_pages = self.get_page_count(summary_path) updated_toc = [(title, page + summary_pages) for title, page in toc_entries] # 合并PDF merger = PdfMerger() # 添加摘要页前验证 self.validate_pdf_file(summary_path) merger.append(summary_path) # 添加其他PDF文件 current_page = summary_pages for pdf, (title, _) in zip(pdf_files, updated_toc): self.validate_pdf_file(pdf) # 文件验证 merger.append(pdf) merger.add_outline_item(title, current_page) current_page += self.get_page_count(pdf) # 写入最终文件 with open(output_path, 'wb') as f: merger.write(f) merger.close() self.log(f"已合并 {len(pdf_files)} 个PDF文件,总大小: {os.path.getsize(output_path) // 1024}KB") return True except Exception as e: self.log(f"合并失败: {str(e)}") return False finally: # 清理临时文件 if os.path.exists(summary_path): os.remove(summary_path) def validate_pdf_file(self, file_path): """验证PDF文件是否有效""" if not os.path.exists(file_path): raise FileNotFoundError(f"文件不存在: {file_path}") if os.path.getsize(file_path) == 0: raise ValueError(f"空文件: {file_path}") # 尝试读取文件验证完整性 with open(file_path, 'rb') as f: reader = PdfReader(f) if len(reader.pages) == 0: raise ValueError(f"无效PDF文件: 无页面内容") def create_summary_page(self, all_tables, output_path): try: # 注册字体 try: font_path = r"C:\Windows\Fonts\simsun.ttc" if os.path.exists(font_path): pdfmetrics.registerFont(TTFont('SimSun', font_path)) pdfmetrics.registerFont(TTFont('SimSunBold', font_path)) from reportlab.lib.fonts import addMapping addMapping('SimSun', 0, 0, 'SimSun') addMapping('SimSun', 1, 0, 'SimSunBold') font_name = 'SimSun' else: font_name = "Helvetica" except Exception as e: font_name = "Helvetica" # 创建PDF c = canvas.Canvas(output_path, pagesize=A4) width, height = A4 # 标题 c.setFont("Helvetica-Bold" if font_name == "Helvetica" else "SimSunBold", 24) c.setFillColorRGB(1, 0, 0) c.drawCentredString(width / 2, height - 50, "摘要") c.setFillColorRGB(0, 0, 0) # 收集表格数据 table_data = [] try: if all_tables and len(all_tables) > 0: # 检查第一个表格是否有数据(至少包含表头和数据行) if len(all_tables[0]) > 1: # 构建表头:第一列“来源”,其他列为表格的表头(假设所有表格结构相同) header = ["来源"] + list(all_tables[0][0]) table_data.append(header) # 遍历每个表格 for idx, table in enumerate(all_tables): # 从表格的第二行开始(跳过表头) for row in table[1:]: # 每行第一列为表格序号(如“表格1”) new_row = [f"表格{idx + 1}"] + list(row) table_data.append(new_row) else: self.log(f"警告:表格{idx + 1}数据不足,跳过") else: self.log("摘要生成:all_tables为空") except Exception as e: self.log(f"表格数据处理异常: {str(e)}") # 创建PDF c = canvas.Canvas(output_path, pagesize=A4) width, height = A4 # 标题 c.setFont("Helvetica-Bold" if font_name == "Helvetica" else "SimSunBold", 24) c.setFillColorRGB(1, 0, 0) c.drawCentredString(width / 2, height - 50, "摘要") c.setFillColorRGB(0, 0, 0) # 如果有表格数据,则创建表格 if table_data: num_cols = len(table_data[0]) col_widths = [140] + [100] * (num_cols - 1) # 第一列稍宽 t = RLTable(table_data, colWidths=col_widths) # 表格样式(使用注册的字体名称) style = TableStyle([ ('BACKGROUND', (0, 0), (-1, 0), colors.lightgrey), ('TEXTCOLOR', (0, 0), (-1, 0), colors.black), ('ALIGN', (0, 0), (-1, -1), 'CENTER'), ('FONTNAME', (0, 0), (-1, -1), font_name), ('FONTSIZE', (0, 0), (-1, 0), 12), ('BOTTOMPADDING', (0, 0), (-1, 0), 12), ('BACKGROUND', (0, 1), (-1, -1), colors.white), ('GRID', (0, 0), (-1, -1), 1, colors.black), ('SPAN', (0, 0), (-1, 0)), ('ALIGN', (0, 0), (0, 0), 'LEFT'), ('FONTNAME', (0, 0), (0, 0), font_name), ('ALIGN', (0, 1), (-1, 1), 'CENTER'), ('FONTNAME', (0, 1), (-1, 1), 'SimSunBold' if font_name == 'SimSun' else 'Helvetica-Bold'), ]) t.setStyle(style) t.wrapOn(c, width - 100, height) t.drawOn(c, 50, height - 500) else: c.setFont(font_name, 14) c.drawString(100, height - 150, "未提取到表格数据") c.save() return True except Exception as e: # 回退机制 try: c = canvas.Canvas(output_path, pagesize=A4) width, height = A4 c.setFont("Helvetica", 14) c.drawString(100, height - 150, "摘要生成失败: 字体配置问题") c.drawString(100, height - 180, f"错误详情: {str(e)}") c.save() return True except: return False if __name__ == "__main__": root = tk.Tk() app = PDFConverterApp(root) root.mainloop() [10:29:36] 输出路径设置为: D:/tes/新建文件夹/111 [10:29:41] 已添加文件夹: D:/tes/新建文件夹/1 [10:29:45] 已添加文件夹: D:/tes/新建文件夹/2 [10:29:46] 已备份Word文件: Lux-H_PA0701_B41-qet1801_0905_simulation_result [10:29:52] 已转换: Lux-H_PA0701_B41-qet1801_0905_simulation_result.docx → PDF [10:29:52] 已备份Word文件: Lux-H_PA0701_B41-qet1802_0905_simulation_result [10:29:56] 已转换: Lux-H_PA0701_B41-qet1802_0905_simulation_result.docx → PDF [10:29:57] 表格数据处理异常: 0 [10:29:57] 已合并 2 个PDF文件,总大小: 995KB [10:29:57] 处理完成!输出文件: D:/tes/新建文件夹/111\听筒磁干扰_结果报告.pdf 分析报错并且在原代码修改
10-01
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值