吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2208|回复: 15
收起左侧

[Python 原创] 批量替换文本文件 新增对 office 文档处理

  [复制链接]
宝宝丷 发表于 2024-5-29 16:49
本帖最后由 宝宝丷 于 2024-7-8 10:02 编辑

微信截图_20240529165214.png

批量替换工具使用指南

本工具用于在文本文件、Word 文档和 Excel 表格中批量替换字符串。以下是使用该工具的详细指南。

安装依赖

在使用本工具之前,您需要确保你已经安装了Python,并安装以下依赖库::

# 依赖列表

## 核心依赖

- **Python**: 程序的运行环境。
- **Tkinter**: 用于构建图形用户界面(GUI)。
- **re**: 提供正则表达式的支持,用于复杂的字符串匹配与替换操作。

## 文件操作

- **os**: 用于处理文件和目录操作,如遍历文件夹和文件路径管理。
- **python-docx**: 用于操作 Word 文档(.docx)文件。
- **openpyxl**: 用于操作 Excel 工作簿(.xlsx)文件。

## 对话框和消息框

- **tkinter.filedialog**: 提供文件选择对话框,用于选择目录和文件。
- **tkinter.messagebox**: 用于显示警告、错误等消息。

## 其他

- **ttk**: Tkinter 的扩展组件库,提供更多的样式化组件。

功能特性

  • 支持文件类型:支持 .txt、.docx 和 .xlsx 文件的字符串批量替换。
  • 正则表达式:支持使用正则表达式进行复杂的替换模式。
  • 备份功能:可选是否为修改前的文件创建备份。

使用界面介绍

工具界面包括以下部分:

1. 目录选择:选择需要进行批量替换操作的文件夹。
2. 旧字符串输入框:输入需要被替换的字符串或正则表达式。
3. 新字符串输入框:输入新的字符串或正则表达式的替换结果。
4. 使用正则表达式选择:选择是否使用正则表达式替换。
5. 创建备份复选框:选择是否为每个被修改的文件创建备份。
6. 日志显示区域:显示操作的详细日志,包括成功或失败的信息。
7. 进度条和进度信息:显示当前的替换进度。
8. 开始按钮:点击开始执行批量替换操作。

操作步骤

1. 启动程序:运行 Python 脚本启动用户界面。
2. 选择目录:点击“选择目录”按钮,选择包含目标文件的文件夹。
3. 输入字符串:在“旧字符串”输入框中输入想要替换的内容,然后在“新字符串”输入框中输入替换后的内容。
4. 设置选项

  • 若需使用正则表达式,请在“使用正则表达式”下拉菜单中选择“是”。
  • 若需备份文件,请确保“创建备份”复选框被勾选。

5. 开始替换:点击“开始替换”按钮,程序将遍历所选目录中的所有支持的文件,并执行替换操作。
6. 查看日志和进度:在界面下方的日志框中查看操作日志,进度条显示替换进度。

注意事项

  • 使用正则表达式时,请确保您的表达式正确无误,以免发生不预期的替换。
  • 创建备份可以防止数据丢失,特别是在处理重要文件时建议开启此功能。
  • 确保文件在替换过程中不被其他程序占用,这可能导致替换失败。
  • 通过以上步骤,您可以方便地使用本工具进行文件内容的批量替换,无论是简单的字符串替换还是复杂的正则表达式替换。如果遇到任何问题,可参考日志- 信息排查或寻求技术支持。

更新日志

v1.2.0 - 最新更新

  • 新增功能:支持 .docx 和 .xlsx 文件的字符串批量替换。
  • 性能优化:改进了文件处理的效率,减少内存使用。

v1.1.0

  • 新增功能:添加了正则表达式替换支持。
  • 用户界面改进:优化了用户界面的响应性和可用性。

v1.0.0

  • 初始发布:支持基本的文本文件.txt中的字符串批量替换。
  • 基础功能:包括文件夹选择、字符串输入、备份选项和进度条显示。

import re
import os
import tkinter as tk
from tkinter import filedialog, messagebox, ttk
from tkinter.scrolledtext import ScrolledText
from docx import Document
from openpyxl import load_workbook

class BatchReplaceApp:
    def __init__(self, root):
        self.root = root
        self.root.title("批量替换工具")
        self.root.geometry("900x800")
        self.root.configure(bg='#F0F0F0')

        self.style = ttk.Style()
        self.style.configure('TButton', font=('Segoe UI', 10), padding=6)
        self.style.configure('TEntry', font=('Segoe UI', 10))
        self.style.configure('TLabel', font=('Segoe UI', 10), background='#F0F0F0')
        self.style.configure('TCheckbutton', font=('Segoe UI', 10), background='#F0F0F0')

        self.create_widgets()

    def create_widgets(self):
        frame = ttk.Frame(self.root, padding="10 10 10 10")
        frame.pack(fill=tk.BOTH, expand=True)

        frame.grid_rowconfigure(5, weight=1)
        frame.grid_columnconfigure(1, weight=1)

        self.directory_label = ttk.Label(frame, text="目录:")
        self.directory_label.grid(row=0, column=0, sticky=tk.W, pady=(20, 5))

        self.directory_entry = ttk.Entry(frame, width=50)
        self.directory_entry.grid(row=0, column=1, pady=(20, 5), padx=(0, 10), sticky=tk.EW)

        self.select_directory_button = ttk.Button(frame, text="选择目录", command=self.select_directory)
        self.select_directory_button.grid(row=0, column=2, pady=(20, 5))

        self.old_str_label = ttk.Label(frame, text="旧字符串:")
        self.old_str_label.grid(row=1, column=0, sticky=tk.W, pady=5)

        self.old_str_entry = ttk.Entry(frame, width=50)
        self.old_str_entry.grid(row=1, column=1, pady=5, padx=(0, 10), sticky=tk.EW)

        self.new_str_label = ttk.Label(frame, text="新字符串:")
        self.new_str_label.grid(row=2, column=0, sticky=tk.W, pady=5)

        self.new_str_entry = ttk.Entry(frame, width=50)
        self.new_str_entry.grid(row=2, column=1, pady=5, padx=(0, 10), sticky=tk.EW)

        self.regex_label = ttk.Label(frame, text="使用正则表达式:")
        self.regex_label.grid(row=3, column=0, sticky=tk.W, pady=5)

        self.use_regex_var = tk.StringVar()
        self.use_regex_combobox = ttk.Combobox(frame, textvariable=self.use_regex_var, state="readonly", values=["是", "否"])
        self.use_regex_combobox.current(1)
        self.use_regex_combobox.grid(row=3, column=1, pady=5, padx=(0, 10), sticky=tk.W)

        self.create_backup_var = tk.BooleanVar(value=True)
        self.create_backup_checkbox = ttk.Checkbutton(frame, text="创建备份", variable=self.create_backup_var)
        self.create_backup_checkbox.grid(row=4, column=0, sticky=tk.W, pady=5)

        self.log_text = ScrolledText(frame, height=10, width=70, wrap=tk.WORD, font=('Segoe UI', 10))
        self.log_text.grid(row=5, column=0, columnspan=3, pady=5, padx=(0, 10), sticky=tk.NSEW)

        self.progress_bar = ttk.Progressbar(frame, orient="horizontal", length=400, mode="determinate")
        self.progress_bar.grid(row=6, column=0, columnspan=3, pady=20, sticky=tk.EW)

        self.progress_label = ttk.Label(frame, text="")
        self.progress_label.grid(row=7, column=0, columnspan=3, pady=5)

        self.start_button = ttk.Button(frame, text="开始替换", command=self.start_replacing)
        self.start_button.grid(row=8, column=0, columnspan=3, pady=20)

    def select_directory(self):
        directory = filedialog.askdirectory()
        if directory:
            self.directory_entry.delete(0, tk.END)
            self.directory_entry.insert(0, directory)

    def start_replacing(self):
        directory = self.directory_entry.get()
        old_str = self.old_str_entry.get()
        new_str = self.new_str_entry.get()
        use_regex = self.use_regex_var.get() == "是"
        create_backup = self.create_backup_var.get()

        # 校验输入
        if not directory:
            messagebox.showwarning("错误", "请选择一个目录.")
            return
        if not old_str:
            messagebox.showwarning("错误", "请输入旧字符串.")
            return
        if not new_str:
            messagebox.showwarning("错误", "请输入新字符串.")
            return

        self.log_text.delete(1.0, tk.END)
        self.progress_bar["value"] = 0

        files_to_replace = []
        for root, dirs, files in os.walk(directory):
            for file in files:
                if file.endswith(('.txt', '.docx', '.xlsx')):
                    files_to_replace.append(os.path.join(root, file))

        if not files_to_replace:
            messagebox.showinfo("信息", "没有找到任何文件。")
            return

        self.progress_bar["maximum"] = len(files_to_replace)

        total_replacements = 0  # 统计总的替换次数
        for index, file_path in enumerate(files_to_replace):
            replacements = self.replace_in_file(file_path, old_str, new_str, use_regex, create_backup)
            total_replacements += replacements  # 累加每个文件的替换次数
            self.progress_bar["value"] = index + 1
            self.progress_label.config(text=f"进度: {index + 1}/{len(files_to_replace)}")
            self.root.update_idletasks()

        messagebox.showinfo("完成", f"所有文件处理完毕! 共进行了 {total_replacements} 次替换。")

    def replace_in_file(self, file_path, old_str, new_str, use_regex, create_backup):
        try:
            replacements = 0  # 每个文件的替换次数
            if file_path.endswith('.txt'):
                replacements = self.replace_in_text_file(file_path, old_str, new_str, use_regex, create_backup)
            elif file_path.endswith('.docx'):
                replacements = self.replace_in_docx_file(file_path, old_str, new_str, use_regex, create_backup)
            elif file_path.endswith('.xlsx'):
                replacements = self.replace_in_xlsx_file(file_path, old_str, new_str, use_regex, create_backup)

            self.log_text.insert(tk.END, f"成功替换: {file_path},替换次数: {replacements}\n")
            return replacements
        except Exception as e:
            self.log_text.insert(tk.END, f"替换失败: {file_path} - {str(e)}\n")
            return 0  # 失败则替换次数为 0

    def replace_in_text_file(self, file_path, old_str, new_str, use_regex, create_backup):
        with open(file_path, 'r', encoding='utf-8') as file:
            content = file.read()

        if use_regex:
            new_content, count = re.subn(old_str, new_str, content, flags=re.MULTILINE)
            replacements = count
        else:
            new_content = content.replace(old_str, new_str)
            replacements = content.count(old_str)

        if create_backup:
            backup_file_path = file_path + '.bak'
            with open(backup_file_path, 'w', encoding='utf-8') as backup_file:
                backup_file.write(content)

        with open(file_path, 'w', encoding='utf-8') as file:
            file.write(new_content)

        return replacements

    def replace_in_docx_file(self, file_path, old_str, new_str, use_regex, create_backup):
        doc = Document(file_path)
        replacements = 0  # 记录文档中的替换次数

        for para in doc.paragraphs:
            if use_regex:
                para.text, count = re.subn(old_str, new_str, para.text, flags=re.MULTILINE)
                replacements += count
            else:
                original_text = para.text
                para.text = para.text.replace(old_str, new_str)
                replacements += original_text.count(old_str)

        for table in doc.tables:
            for row in table.rows:
                for cell in row.cells:
                    if use_regex:
                        cell.text, count = re.subn(old_str, new_str, cell.text, flags=re.MULTILINE)
                        replacements += count
                    else:
                        original_text = cell.text
                        cell.text = cell.text.replace(old_str, new_str)
                        replacements += original_text.count(old_str)

        if create_backup:
            backup_file_path = file_path + '.bak'
            doc.save(backup_file_path)

        doc.save(file_path)

        return replacements

    def replace_in_xlsx_file(self, file_path, old_str, new_str, use_regex, create_backup):
        workbook = load_workbook(file_path)
        replacements = 0  # 记录工作簿中的替换次数

        for sheet in workbook.worksheets:
            for row in sheet.iter_rows():
                for cell in row:
                    if cell.value and isinstance(cell.value, str):
                        if use_regex:
                            cell.value, count = re.subn(old_str, new_str, cell.value, flags=re.MULTILINE)
                            replacements += count
                        else:
                            original_value = cell.value
                            cell.value = cell.value.replace(old_str, new_str)
                            replacements += original_value.count(old_str)

        if create_backup:
            backup_file_path = file_path + '.bak'
            workbook.save(backup_file_path)

        workbook.save(file_path)

        return replacements

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

免费评分

参与人数 4吾爱币 +10 热心值 +4 收起 理由
苏紫方璇 + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
dookp + 1 + 1 谢谢@Thanks!
xinxin99 + 1 + 1 用心讨论,共获提升!
chadd + 1 + 1 热心回复!

查看全部评分

本帖被以下淘专辑推荐:

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

Hamon 发表于 2024-5-29 20:46
加大难度,可以整个 office 文档处理的
老街518 发表于 2024-9-11 10:37
个Word的第一行,我有几千个Word,我需要批量把这几千个Word中的第一行,也就是标题替换成我需要的标题,需要替换的标题我整理到了一个txt里面,也可以放到Excel里面,然后进行批量替换这几千个Word。

比如我有3000个Word,需要把这3000个Word中的第一行也就是标题,每个Word的第一行就是标题,替换成我需要的标题。

然后我先整理标题列表txt,我把3000个需要替换的标题放到这个txt中

请问如何替换呢,比如3000个Word和1.txt列表我放到文件夹 【Word】中,我需要如何做呢,这个软件能加个这个功能不,大神?
 楼主| 宝宝丷 发表于 2024-5-29 16:59
感觉很乱 ,不太会排版

点评

[md]图文混排可以参考: - [Markdown 插件使用说明](https://www.52pojie.cn/thread-717627-1-1.html) - [【公告】发帖代码插入以及添加链接教程(有福利)](https://www.52pojie.cn/thread-713042-1-1.html)  详情 回复 发表于 2024-5-30 08:49
奈酱 发表于 2024-5-29 17:18
可以字与字之间批量加空格
lvtaode0657 发表于 2024-5-29 19:03
很不错哦。辛苦了
dookp 发表于 2024-5-29 20:13
实用,感谢分享
afti 发表于 2024-5-29 21:11
看看文本替换效果如何
mubenxinsheng 发表于 2024-5-29 21:30
感谢分享
爱飞的猫 发表于 2024-5-30 08:49
宝宝丷 发表于 2024-5-29 16:59
感觉很乱 ,不太会排版

图文混排可以参考:

推荐使用 Markdown 插件,可以在本地排版好然后提交。

免费评分

参与人数 1吾爱币 +1 热心值 +1 收起 理由
宝宝丷 + 1 + 1 谢谢@Thanks!

查看全部评分

xiao_1245 发表于 2024-6-4 21:33
感谢分享,我辈楷模
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

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

GMT+8, 2024-12-14 08:01

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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