吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 1766|回复: 13
收起左侧

[Python 原创] Txt文档批量修改替换文本(带界面)

  [复制链接]
Eks6666 发表于 2025-7-26 15:51
[Python] 纯文本查看 复制代码
import os
import tkinter as tk
from tkinter import filedialog, ttk, messagebox
import threading
import re

class TxtBatchEditor:
    def __init__(self, root):
        self.root = root
        self.root.title("TXT文件批量修改工具")
        self.root.geometry("700x500")
        self.root.resizable(True, True)
        
        # 设置中文字体支持
        self.style = ttk.Style()
        self.style.configure("TLabel", font=("SimHei", 10))
        self.style.configure("TButton", font=("SimHei", 10))
        self.style.configure("TEntry", font=("SimHei", 10))
        self.style.configure("TText", font=("SimHei", 10))
        
        # 选择文件夹
        self.folder_frame = ttk.Frame(root, padding="10")
        self.folder_frame.pack(fill=tk.X)
        
        ttk.Label(self.folder_frame, text="目标文件夹:").pack(side=tk.LEFT, padx=5)
        
        self.folder_path = tk.StringVar()
        self.folder_entry = ttk.Entry(self.folder_frame, textvariable=self.folder_path, width=50)
        self.folder_entry.pack(side=tk.LEFT, padx=5, fill=tk.X, expand=True)
        
        self.browse_btn = ttk.Button(self.folder_frame, text="浏览...", command=self.browse_folder)
        self.browse_btn.pack(side=tk.LEFT, padx=5)
        
        # 查找替换设置
        self.find_replace_frame = ttk.Frame(root, padding="10")
        self.find_replace_frame.pack(fill=tk.X)
        
        ttk.Label(self.find_replace_frame, text="查找内容:").grid(row=0, column=0, padx=5, pady=5, sticky=tk.W)
        self.find_text = tk.StringVar()
        ttk.Entry(self.find_replace_frame, textvariable=self.find_text, width=40).grid(row=0, column=1, padx=5, pady=5, sticky=tk.W)
        
        ttk.Label(self.find_replace_frame, text="替换为:").grid(row=1, column=0, padx=5, pady=5, sticky=tk.W)
        self.replace_text = tk.StringVar()
        ttk.Entry(self.find_replace_frame, textvariable=self.replace_text, width=40).grid(row=1, column=1, padx=5, pady=5, sticky=tk.W)
        
        # 选项设置
        self.options_frame = ttk.Frame(root, padding="10")
        self.options_frame.pack(fill=tk.X)
        
        self.case_sensitive = tk.BooleanVar(value=False)
        ttk.Checkbutton(self.options_frame, text="区分大小写", variable=self.case_sensitive).pack(side=tk.LEFT, padx=10)
        
        self.use_regex = tk.BooleanVar(value=False)
        ttk.Checkbutton(self.options_frame, text="使用正则表达式", variable=self.use_regex).pack(side=tk.LEFT, padx=10)
        
        # 按钮区域
        self.buttons_frame = ttk.Frame(root, padding="10")
        self.buttons_frame.pack(fill=tk.X)
        
        self.start_btn = ttk.Button(self.buttons_frame, text="开始替换", command=self.start_replacement)
        self.start_btn.pack(side=tk.LEFT, padx=5)
        
        self.cancel_btn = ttk.Button(self.buttons_frame, text="取消", command=self.cancel_replacement, state=tk.DISABLED)
        self.cancel_btn.pack(side=tk.LEFT, padx=5)
        
        self.clear_log_btn = ttk.Button(self.buttons_frame, text="清空日志", command=self.clear_log)
        self.clear_log_btn.pack(side=tk.RIGHT, padx=5)
        
        # 进度条
        self.progress_frame = ttk.Frame(root, padding="10")
        self.progress_frame.pack(fill=tk.X)
        
        self.progress_var = tk.DoubleVar()
        self.progress_bar = ttk.Progressbar(self.progress_frame, variable=self.progress_var, maximum=100)
        self.progress_bar.pack(fill=tk.X)
        
        # 日志区域
        self.log_frame = ttk.LabelFrame(root, text="操作日志", padding="10")
        self.log_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)
        
        self.log_text = tk.Text(self.log_frame, wrap=tk.WORD, state=tk.DISABLED)
        self.log_text.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        
        scrollbar = ttk.Scrollbar(self.log_frame, command=self.log_text.yview)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        self.log_text.config(yscrollcommand=scrollbar.set)
        
        # 状态变量
        self.processing = False
        self.cancel_requested = False
        
    def browse_folder(self):
        folder = filedialog.askdirectory()
        if folder:
            self.folder_path.set(folder)
            self.log(f"已选择文件夹: {folder}")
    
    def log(self, message):
        """在日志区域显示消息"""
        self.log_text.config(state=tk.NORMAL)
        self.log_text.insert(tk.END, message + "\n")
        self.log_text.see(tk.END)
        self.log_text.config(state=tk.DISABLED)
    
    def clear_log(self):
        self.log_text.config(state=tk.NORMAL)
        self.log_text.delete(1.0, tk.END)
        self.log_text.config(state=tk.DISABLED)
    
    def start_replacement(self):
        """开始替换过程"""
        folder = self.folder_path.get()
        find = self.find_text.get()
        replace = self.replace_text.get()
        
        if not folder:
            messagebox.showerror("错误", "请选择目标文件夹")
            return
        
        if not find:
            messagebox.showerror("错误", "请输入要查找的内容")
            return
        
        # 准备开始处理
        self.processing = True
        self.cancel_requested = False
        self.start_btn.config(state=tk.DISABLED)
        self.cancel_btn.config(state=tk.NORMAL)
        self.browse_btn.config(state=tk.DISABLED)
        
        self.log(f"开始替换操作...")
        self.log(f"文件夹: {folder}")
        self.log(f"查找: {find}")
        self.log(f"替换为: {replace}")
        self.log(f"区分大小写: {'是' if self.case_sensitive.get() else '否'}")
        self.log(f"使用正则表达式: {'是' if self.use_regex.get() else '否'}")
        
        # 在新线程中执行替换操作,避免UI冻结
        threading.Thread(target=self.perform_replacement, args=(folder, find, replace), daemon=True).start()
    
    def cancel_replacement(self):
        if self.processing:
            self.cancel_requested = True
            self.log("正在取消操作...")
            self.cancel_btn.config(text="取消中...")
    
    def perform_replacement(self, folder, find, replace):
        """执行实际的替换操作"""
        try:
            # 获取所有TXT文件
            txt_files = []
            for root_dir, _, files in os.walk(folder):
                for file in files:
                    if file.lower().endswith('.txt'):
                        txt_files.append(os.path.join(root_dir, file))
            
            total_files = len(txt_files)
            if total_files == 0:
                self.root.after(0, lambda: self.log("未找到任何TXT文件"))
                self.root.after(0, self.finish_processing)
                return
            
            self.root.after(0, lambda: self.log(f"找到 {total_files} 个TXT文件"))
            
            modified_files = 0
            
            # 处理每个文件
            for i, file_path in enumerate(txt_files):
                if self.cancel_requested:
                    self.root.after(0, lambda: self.log("操作已取消"))
                    break
                
                # 更新进度条
                progress = (i + 1) / total_files * 100
                self.root.after(0, lambda p=progress: self.progress_var.set(p))
                
                # 读取文件内容
                try:
                    with open(file_path, 'r', encoding='utf-8') as f:
                        content = f.read()
                except UnicodeDecodeError:
                    # 尝试其他编码
                    try:
                        with open(file_path, 'r', encoding='gbk') as f:
                            content = f.read()
                    except:
                        self.root.after(0, lambda fp=file_path: self.log(f"无法读取文件: {fp}(编码问题)"))
                        continue
                except Exception as e:
                    self.root.after(0, lambda fp=file_path, err=str(e): self.log(f"读取文件 {fp} 出错: {err}"))
                    continue
                
                # 执行替换
                new_content = content
                if self.use_regex.get():
                    # 使用正则表达式替换
                    flags = 0 if self.case_sensitive.get() else re.IGNORECASE
                    try:
                        new_content, count = re.subn(find, replace, content, flags=flags)
                    except re.error as e:
                        self.root.after(0, lambda err=str(e): self.log(f"正则表达式错误: {err}"))
                        self.root.after(0, self.finish_processing)
                        return
                else:
                    # 普通文本替换
                    if self.case_sensitive.get():
                        count = content.count(find)
                        if count > 0:
                            new_content = content.replace(find, replace)
                    else:
                        # 不区分大小写的替换
                        count = 0
                        new_content = ""
                        start = 0
                        content_lower = content.lower()
                        find_lower = find.lower()
                        len_find = len(find)
                        
                        while True:
                            pos = content_lower.find(find_lower, start)
                            if pos == -1:
                                new_content += content[start:]
                                break
                            
                            count += 1
                            new_content += content[start:pos] + replace
                            start = pos + len_find
                
                # 如果内容有变化,保存文件
                if new_content != content:
                    try:
                        with open(file_path, 'w', encoding='utf-8') as f:
                            f.write(new_content)
                        modified_files += 1
                        self.root.after(0, lambda fp=file_path, c=count: self.log(f"已修改 {fp}(替换 {c} 处)"))
                    except Exception as e:
                        self.root.after(0, lambda fp=file_path, err=str(e): self.log(f"写入文件 {fp} 出错: {err}"))
            
            # 完成处理
            if not self.cancel_requested:
                self.root.after(0, lambda: self.log(f"处理完成,共修改 {modified_files} 个文件"))
        
        except Exception as e:
            self.root.after(0, lambda err=str(e): self.log(f"操作出错: {err}"))
        
        self.root.after(0, self.finish_processing)
    
    def finish_processing(self):
        """完成处理,恢复UI状态"""
        self.processing = False
        self.cancel_requested = False
        self.progress_var.set(100 if not self.cancel_requested else 0)
        self.start_btn.config(state=tk.NORMAL)
        self.cancel_btn.config(state=tk.DISABLED, text="取消")
        self.browse_btn.config(state=tk.NORMAL)
        self.root.after(0, lambda: self.log("操作结束\n"))

if __name__ == "__main__":
    root = tk.Tk()
    app = TxtBatchEditor(root)
    root.mainloop()
    


运行代码后界面长下面这样:
image.png

免费评分

参与人数 5吾爱币 +8 热心值 +5 收起 理由
xiaolongbao + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
kunzzz + 1 + 1 杩欎釜姝e垯...鐗涢??
hrh123 + 5 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
qck + 1 + 1 谢谢@Thanks!
jaffa + 1 谢谢@Thanks!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

lhwei2002 发表于 2025-7-26 16:05
正则表达式太复杂了,看了好久都没搞明白,太强大了
yonjon 发表于 2025-7-26 16:17
唧唧 发表于 2025-7-26 16:22
sunson1097 发表于 2025-7-26 16:58
刚准备学TK ,这不就来了
先简单做个界面试试
riverskywrorld 发表于 2025-7-26 17:30
文件搜索关键词替换也可以
gs18090 发表于 2025-7-26 21:02
一直都没搞懂正则到底是个啥意思
头像被屏蔽
kcx1spb01 发表于 2025-7-26 21:33
提示: 作者被禁止或删除 内容自动屏蔽
adfsd 发表于 2025-7-26 22:28
研究学习一下了
codingH 发表于 2025-7-28 02:45
不错啊,第一次接触python的界面
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - 52pojie.cn ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2026-2-27 12:21

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表