

Python,速成心法
敲代码,查资料,问度娘
练习,探索,总结,优化

★★★★★博文创作不易,我的博文不需要打赏,也不需要知识付费,可以白嫖学习编程小技巧。使用代码的过程中,如有疑问的地方,欢迎大家指正留言交流。喜欢的老铁可以多多点赞+收藏分享+置顶,小红牛在此表示感谢。★★★★★

↓ 源码如下 ↓
# -*- coding: utf-8 -*-# @Author : 小红牛# 微信公众号:wdPythonimport tkinter as tkfrom tkinter import filedialog, scrolledtext, messageboximport difflibimport tempfileimport webbrowserimport osclass DiffViewerApp:def __init__(self, root):self.root = rootself.root.title("difflib模块 综合示例 - 文本差异比较器")self.root.geometry("1000x700")# 创建主框架main_frame = tk.Frame(root)main_frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)# 左侧文本区域left_frame = tk.LabelFrame(main_frame, text="原始文本 (A)", padx=5, pady=5)left_frame.grid(row=0, column=0, sticky="nsew", padx=5, pady=5)self.text_left = scrolledtext.ScrolledText(left_frame, wrap=tk.NONE, font=("Consolas", 10))self.text_left.pack(fill=tk.BOTH, expand=True)btn_left_load = tk.Button(left_frame, text="加载文件", command=lambda: self.load_file(self.text_left))btn_left_load.pack(pady=2)# 右侧文本区域right_frame = tk.LabelFrame(main_frame, text="修改后文本 (B)", padx=5, pady=5)right_frame.grid(row=0, column=1, sticky="nsew", padx=5, pady=5)self.text_right = scrolledtext.ScrolledText(right_frame, wrap=tk.NONE, font=("Consolas", 10))self.text_right.pack(fill=tk.BOTH, expand=True)btn_right_load = tk.Button(right_frame, text="加载文件", command=lambda: self.load_file(self.text_right))btn_right_load.pack(pady=2)# 控制面板control_frame = tk.Frame(main_frame)control_frame.grid(row=1, column=0, columnspan=2, sticky="ew", pady=10)self.mode_var = tk.StringVar(value="ndiff")mode_ndiff = tk.Radiobutton(control_frame, text="行差异 (ndiff)", variable=self.mode_var, value="ndiff")mode_unified = tk.Radiobutton(control_frame, text="统一差异 (unified_diff)", variable=self.mode_var, value="unified")mode_ratio = tk.Radiobutton(control_frame, text="相似度比率", variable=self.mode_var, value="ratio")mode_ndiff.pack(side=tk.LEFT, padx=5)mode_unified.pack(side=tk.LEFT, padx=5)mode_ratio.pack(side=tk.LEFT, padx=5)btn_compare = tk.Button(control_frame, text="比较", command=self.compare_texts, bg="#4CAF50", fg="white")btn_compare.pack(side=tk.LEFT, padx=20)btn_clear = tk.Button(control_frame, text="清空所有", command=self.clear_all, bg="#f44336", fg="white")btn_clear.pack(side=tk.LEFT, padx=5)# 新增:加载示例按钮#btn_example = tk.Button(control_frame, text="加载示例", command=self.load_example, bg="#FF9800", fg="white")#btn_example.pack(side=tk.LEFT, padx=5)# 扩展功能:生成 HTML 差异报告btn_html = tk.Button(control_frame, text="生成 HTML 差异报告 (浏览器打开)", command=self.generate_html_diff, bg="#2196F3", fg="white")btn_html.pack(side=tk.LEFT, padx=5)# 结果显示区域result_frame = tk.LabelFrame(main_frame, text="比较结果", padx=5, pady=5)result_frame.grid(row=2, column=0, columnspan=2, sticky="nsew", padx=5, pady=5)self.text_result = scrolledtext.ScrolledText(result_frame, wrap=tk.NONE, font=("Consolas", 10))self.text_result.pack(fill=tk.BOTH, expand=True)# 配置网格权重,使窗口自适应main_frame.grid_rowconfigure(0, weight=1)main_frame.grid_rowconfigure(2, weight=1)main_frame.grid_columnconfigure(0, weight=1)main_frame.grid_columnconfigure(1, weight=1)# 配置差异结果的颜色标签self.text_result.tag_config("add", foreground="green", background="#e8f5e9")self.text_result.tag_config("delete", foreground="red", background="#ffebee")self.text_result.tag_config("change", foreground="blue", background="#e3f2fd")self.text_result.tag_config("info", foreground="gray", font=("Consolas", 9, "italic"))# 加载示例文件self.load_example()def load_file(self, text_widget):"""加载文本文件到指定的 Text 组件"""filepath = filedialog.askopenfilename(title="选择文本文件",filetypes=[("文本文件", "*.txt"), ("所有文件", "*.*")])if not filepath:returntry:with open(filepath, "r", encoding="utf-8") as f:content = f.read()text_widget.delete(1.0, tk.END)text_widget.insert(1.0, content)except Exception as e:messagebox.showerror("错误", f"无法读取文件:{e}")def get_text(self, text_widget):"""从 Text 组件获取文本(按行分割)"""return text_widget.get(1.0, tk.END).rstrip("\n")def clear_all(self):"""清空所有文本框"""self.text_left.delete(1.0, tk.END)self.text_right.delete(1.0, tk.END)self.text_result.delete(1.0, tk.END)def load_example(self):"""加载预定义的示例文本,展示各种差异类型"""example_left = """我是李白Hello world!This is a simple example.We have a line that will be removed.Another line to demonstrate word changes.Line with numbers: 12345.Final line stays the same."""example_right = """我是杜甫Hello Python!This is a simple example.Another line to demonstrate word changes. (modified)Line with numbers: 12345 and more.Final line stays the same.Brand new line added at the end."""self.text_left.delete(1.0, tk.END)self.text_left.insert(1.0, example_left)self.text_right.delete(1.0, tk.END)self.text_right.insert(1.0, example_right)self.text_result.delete(1.0, tk.END)messagebox.showinfo("示例已加载", "左右两侧已填充示例文本。\n\n包含以下差异:\n- 首行单词变化\n- 中间一行被删除\n- 某行被修改并添加注释\n- 数字序列扩展\n- 末尾新增一行")def compare_texts(self):"""根据选择的模式执行比较"""text_a = self.get_text(self.text_left)text_b = self.get_text(self.text_right)if not text_a and not text_b:messagebox.showinfo("提示", "请在两侧输入文本或加载文件。")returnmode = self.mode_var.get()self.text_result.delete(1.0, tk.END)if mode == "ndiff":self.show_ndiff(text_a, text_b)elif mode == "unified":self.show_unified_diff(text_a, text_b)elif mode == "ratio":self.show_ratio(text_a, text_b)def show_ndiff(self, text_a, text_b):"""使用 difflib.ndiff 显示带颜色标记的行差异"""a_lines = text_a.splitlines()b_lines = text_b.splitlines()diff = difflib.ndiff(a_lines, b_lines)for line in diff:if line.startswith('- '):self.text_result.insert(tk.END, line + "\n", "delete")elif line.startswith('+ '):self.text_result.insert(tk.END, line + "\n", "add")elif line.startswith('? '):self.text_result.insert(tk.END, line + "\n", "change")else:self.text_result.insert(tk.END, line + "\n")def show_unified_diff(self, text_a, text_b):"""显示统一差异格式(类似 diff -u)"""a_lines = text_a.splitlines()b_lines = text_b.splitlines()# 可以自定义上下文行数,这里设为3diff = difflib.unified_diff(a_lines, b_lines, fromfile='原始文本', tofile='修改后文本', lineterm='')diff_text = "\n".join(diff)if not diff_text.strip():self.text_result.insert(tk.END, "两个文本完全相同,没有差异。", "info")else:# 统一差异中,以 + 和 - 开头的行分别标记for line in diff_text.splitlines():if line.startswith('+'):self.text_result.insert(tk.END, line + "\n", "add")elif line.startswith('-'):self.text_result.insert(tk.END, line + "\n", "delete")elif line.startswith('@@'):self.text_result.insert(tk.END, line + "\n", "change")else:self.text_result.insert(tk.END, line + "\n")def show_ratio(self, text_a, text_b):"""计算相似度比率并显示"""seq_matcher = difflib.SequenceMatcher(None, text_a, text_b)ratio = seq_matcher.ratio()quick_ratio = seq_matcher.quick_ratio()real_quick_ratio = seq_matcher.real_quick_ratio()result = (f"相似度分析结果(0~1,越接近1越相似):\n\n"f"ratio() ............ {ratio:.4f}\n"f"quick_ratio() ...... {quick_ratio:.4f}\n"f"real_quick_ratio() . {real_quick_ratio:.4f}\n\n"f"说明:\n"f"- ratio: 基本相似度,考虑所有字符\n"f"- quick_ratio: 快速近似计算\n"f"- real_quick_ratio: 最快但最粗略的估算")self.text_result.insert(tk.END, result, "info")def generate_html_diff(self):"""使用 HtmlDiff 生成 HTML 报告并在默认浏览器中打开"""text_a = self.get_text(self.text_left)text_b = self.get_text(self.text_right)if not text_a and not text_b:messagebox.showinfo("提示", "请在两侧输入文本或加载文件。")returna_lines = text_a.splitlines()b_lines = text_b.splitlines()htmldiff = difflib.HtmlDiff()# 生成完整的 HTML 页面,上下文行数设为3html_content = htmldiff.make_file(a_lines, b_lines, fromdesc='原始文本', todesc='修改后文本', context=True, numlines=3)# 保存到临时文件并打开try:with tempfile.NamedTemporaryFile(mode='w', suffix='.html', delete=False, encoding='utf-8') as f:f.write(html_content)temp_path = f.namewebbrowser.open('file://' + temp_path)# 注意:临时文件不会自动删除,可以在程序关闭时清理,但为了简单起见这里不做处理except Exception as e:messagebox.showerror("错误", f"生成 HTML 报告失败:{e}")if __name__ == "__main__":root = tk.Tk()app = DiffViewerApp(root)root.mainloop()
完毕!!感谢您的收看
--------★★历史博文集合★★--------
