要将 `python-docx` 替换为 `pywin32` 来实现 Word 文档中的文本替换功能,我们需要利用 COM 自动化接口来控制 Microsoft Word 应用程序。以下是修改后的完整代码:
### 修改点说明:
1. **引入 pywin32 相关模块**:`win32com.client` 和 `pythoncom` 是 `pywin32` 提供的核心模块。
2. **创建 Word 应用实例**:通过 COM 创建一个 Word 应用实例,并打开指定的 .docx 文件。
3. **替换文档中的文本**:遍历文档的所有段落并进行文本替换操作。
4. **保存和关闭文档**:在替换完成后保存更改并关闭文档。
下面是完整的 Python 代码示例:
```python
import re
import os
import tkinter as tk
from tkinter import filedialog, messagebox, scrolledtext
import win32com.client as win32
import pythoncom
class WordContentReplacer:
@staticmethod
def wildcard_to_regex(pattern):
"""
Convert a Word-like wildcard pattern to a regex pattern.
Args:
pattern (str): The wildcard pattern string from the user input.
Returns:
str: Converted regex pattern.
"""
special_chars = {
'?': '.',
'*': '.*',
'[': '[',
']': ']',
'^': '\\^',
'$': '\\$',
'.': '\\.',
'+': '\\+',
'-': '\\-',
'|': '\\|',
'(': '\\(',
')': '\\)',
}
regex_pattern = ''
escape_next = False
for char in pattern:
if escape_next:
regex_pattern += '\\' + char
escape_next = False
continue
if char == '\\':
escape_next = True
continue
if char in special_chars:
regex_pattern += special_chars[char]
else:
regex_pattern += re.escape(char) # Escape all other characters
return regex_pattern
@staticmethod
def replace_text_in_doc(file_path, find_pattern, replace_text, use_wildcards=False, log_func=None):
if use_wildcards:
find_pattern = WordContentReplacer.wildcard_to_regex(find_pattern)
# Create an instance of Word application
word_app = win32.DispatchEx('Word.Application')
word_app.Visible = False
doc = None
try:
doc = word_app.Documents.Open(file_path)
found = False
# Process paragraphs
for para in doc.Paragraphs:
original_text = para.Range.Text.strip()
updated_text = re.sub(find_pattern, replace_text, original_text)
if updated_text != original_text:
para.Range.Text = updated_text
found = True
if log_func:
log_func(f"Paragraph modified: '{original_text}' -> '{updated_text}'\n")
# Save changes
if found:
doc.Save()
return found
finally:
if doc is not None:
doc.Close(SaveChanges=0) # Do not save changes on close
word_app.Quit()
class FileRenamerAndWordEditorApp:
def __init__(self, master):
self.master = master
master.title("文件批量重命名及Word内容替换工具 v1.0")
self.log_text = scrolledtext.ScrolledText(master, wrap=tk.WORD, width=80, height=20)
self.log_text.grid(row=4, column=0, columnspan=3, padx=10, pady=5, sticky="ew")
self.create_widgets()
def log(self, message):
self.log_text.insert(tk.END, message)
self.log_text.yview(tk.END)
def create_widgets(self):
# 文件夹选择部分
tk.Label(self.master, text="目标文件夹:").grid(row=0, column=0, padx=5, pady=5, sticky="w")
self.folder_path = tk.StringVar()
tk.Entry(self.master, textvariable=self.folder_path, width=40).grid(row=0, column=1, padx=5)
tk.Button(self.master, text="浏览...", command=self.select_folder).grid(row=0, column=2, padx=5)
# 重命名选项部分
options_frame = tk.LabelFrame(self.master, text="重命名选项")
options_frame.grid(row=1, column=0, columnspan=3, padx=10, pady=5, sticky="ew")
tk.Label(options_frame, text="添加前缀:").grid(row=0, column=0, padx=5, sticky="e")
self.prefix_entry = tk.Entry(options_frame, width=25)
self.prefix_entry.grid(row=0, column=1, pady=2)
tk.Label(options_frame, text="添加后缀:").grid(row=1, column=0, padx=5, sticky="e")
self.suffix_entry = tk.Entry(options_frame, width=25)
self.suffix_entry.grid(row=1, column=1, pady=2)
tk.Label(options_frame, text="查找内容:").grid(row=2, column=0, padx=5, sticky="e")
self.find_entry = tk.Entry(options_frame, width=25)
self.find_entry.grid(row=2, column=1, pady=2)
tk.Label(options_frame, text="替换为:").grid(row=3, column=0, padx=5, sticky="e")
self.replace_entry = tk.Entry(options_frame, width=25)
self.replace_entry.grid(row=3, column=1, pady=2)
# Word内容替换部分
word_options_frame = tk.LabelFrame(self.master, text="Word内容替换选项")
word_options_frame.grid(row=2, column=0, columnspan=3, padx=10, pady=5, sticky="ew")
tk.Label(word_options_frame, text="查找内容及格式:").grid(row=0, column=0, padx=5, pady=5, sticky="ne")
self.word_find_text = scrolledtext.ScrolledText(word_options_frame, wrap=tk.WORD, width=40, height=6)
self.word_find_text.grid(row=0, column=1, padx=5, pady=5)
tk.Label(word_options_frame, text="替换为及格式:").grid(row=1, column=0, padx=5, pady=5, sticky="ne")
self.word_replace_text = scrolledtext.ScrolledText(word_options_frame, wrap=tk.WORD, width=40, height=6)
self.word_replace_text.grid(row=1, column=1, padx=5, pady=5)
# 添加通配符选项的复选框
self.use_wildcards_var = tk.BooleanVar(value=False)
tk.Checkbutton(
word_options_frame,
text="使用通配符",
variable=self.use_wildcards_var
).grid(row=2, column=0, columnspan=2, padx=5, pady=5, sticky="nw")
# 操作按钮
tk.Button(self.master, text="执行重命名", command=self.execute_rename, bg="#4CAF50", fg="white").grid(row=3, column=0, pady=10)
tk.Button(self.master, text="执行Word内容替换", command=self.execute_word_replace, bg="#4CAF50", fg="white").grid(row=3, column=1, pady=10)
def select_folder(self):
"""选择目标文件夹"""
folder_selected = filedialog.askdirectory()
if folder_selected:
self.folder_path.set(folder_selected)
def execute_rename(self):
"""执行重命名操作"""
folder = self.folder_path.get()
prefix = self.prefix_entry.get().strip()
suffix = self.suffix_entry.get().strip()
find_str = self.find_entry.get().strip()
replace_str = self.replace_entry.get().strip()
if not folder:
messagebox.showerror("错误", "请先选择目标文件夹")
return
try:
renamed_files = []
for filename in os.listdir(folder):
old_path = os.path.join(folder, filename)
if os.path.isfile(old_path): # 只处理文件
new_name = filename
if find_str:
new_name = new_name.replace(find_str, replace_str)
if prefix:
new_name = prefix + new_name
if suffix:
name, ext = os.path.splitext(new_name)
new_name = f"{name}{suffix}{ext}"
new_path = os.path.join(folder, new_name)
if new_path != old_path:
os.rename(old_path, new_path)
renamed_files.append((old_path, new_path))
if renamed_files:
details = "\n".join([f"{old} -> {new}" for old, new in renamed_files])
self.log(f"以下文件被重命名:\n{details}\n")
messagebox.showinfo("完成", f"文件重命名操作已成功完成!共重命名了 {len(renamed_files)} 个文件。\n详情见日志窗口。")
else:
self.log("没有需要重命名的文件。\n")
messagebox.showinfo("完成", "所有文件已经是最新的名称,无需重命名。")
except Exception as e:
messagebox.showerror("错误", f"操作失败:{str(e)}")
self.log(f"重命名操作失败: {str(e)}\n")
def execute_word_replace(self):
"""执行Word内容替换操作"""
folder = self.folder_path.get()
find_text = self.word_find_text.get("1.0", tk.END).strip()
replace_text = self.word_replace_text.get("1.0", tk.END).strip()
if not folder:
messagebox.showerror("错误", "请选择目标文件夹")
return
if not find_text or not replace_text:
messagebox.showerror("错误", "请输入查找内容和替换内容")
return
try:
processed_files = []
for filename in os.listdir(folder):
if filename.endswith(".docx"):
file_path = os.path.join(folder, filename)
if WordContentReplacer.replace_text_in_doc(file_path, find_text, replace_text, self.use_wildcards_var.get(), lambda msg: self.log(msg)):
processed_files.append(filename)
if processed_files:
details = "\n".join(processed_files)
self.log(f"以下文件的内容进行了替换:\n{details}\n")
messagebox.showinfo("完成", f"Word文档内容替换操作已完成!共替换了 {len(processed_files)} 个文件。\n详情见日志窗口。")
else:
self.log("没有找到需要替换内容的文件。\n")
messagebox.showinfo("完成", "所有Word文档内容已经是最新状态,无需替换。")
except Exception as e:
messagebox.showerror("错误", f"操作失败:{str(e)}")
self.log(f"Word内容替换操作失败: {str(e)}\n")
if __name__ == "__main__":
root = tk.Tk()
app = FileRenamerAndWordEditorApp(root)
root.mainloop()
```
### 注意事项:
- 使用 `pywin32` 需要安装相应的包:可以通过命令 `pip install pywin32` 安装。
- 这种方法依赖于本地安装有 Microsoft Office(特别是 Word),因此适用于 Windows 平台。
- 在某些情况下,可能需要以管理员权限运行脚本来避免访问权限问题。
这样就可以利用 `pywin32` 实现对 Word 文档中特定文本的查找与替换了。希望这段代码能够满足您的需求。如果有任何疑问或需要进一步的帮助,请随时告知。