乐于分享
好东西不私藏

fixWord!升级!全新D版本来袭!

fixWord!升级!全新D版本来袭!

fixWord
又!升!级!了!
V4.3.5
此版本进行了多个问题的修复
识别更准确
响应速度更快
体验更友好
欢迎使用
!!!
此外
全新D(DIY)版本v1.1.3已发布

支持用户自定义输出格式:

页边距、字体、字号、行距、各级标题格式等

批量处理;

配置保存/导入;

访问主页(Gitee)https://gitee.com/cxmStudio/fixWord/tree/main/fixWord_D
访问主页(Github)
https://github.com/Sam-CXM/fixWord/tree/main/fixWord_D
手动选择/点击按钮选择文件或文件夹路径
点击【开始处理】按钮即可快速处理
详细内容见下文

一、前期准备

  • 开发工具
VisualStudio Code
  • 编程语言
Python
  • 第三方库
python-docx
    pyinstaller
    pillow
二、功能
  • 标题
  • 一级标题
  • 二级标题
  • 三级标题
  • 段落间距
  • 页边距
  • 页码
  • 数字、英文
  • 图片?
  • 其他
    字体、字号、替换文字(符号)
三、部分代码
  • 导入库
from docx import Documentfrom docx.shared import Pt, Cm  # 用来设置字体的大小from docx.oxml.ns import qn  # 设置字体from docx.enum.text import WD_ALIGN_PARAGRAPH, WD_PARAGRAPH_ALIGNMENT  # 设置对其方式from docx.oxml import OxmlElementfrom os import listdir, path, makedirs, getcwd, startfilefrom tkinter import Tk, Entry, Button, Label, filedialog, messagebox, SUNKEN, Radiobutton, Frame, ttk, Listbox, StringVar, END, Toplevel, Canvas, Menufrom time import localtime, strftimefrom PIL import Image, ImageTkfrom webbrowser import open as webopen
  • 标题
run_title = p.add_run(i)if is_digit == "num_or_let":    run_title.font.name = NUMBERFONTelse:    run_title.font.name = TITLEFONT    run_title._element.rPr.rFonts.set(qn('w:eastAsia'), TITLEFONT)if version_ipt == "school":    run_title.font.size = Pt(FONTSIZEDICT["小二号"])else:    run_title.font.size = Pt(FONTSIZEDICT["二号"])
  • 一级标题
index1_list = ["一、""二、""三、""四、""五、""六、""七、""八、""九、""十、""十一、""十二、""十三、""十四、""十五、""十六、""十七、""十八、""十九、""二十、"]for i in index1_list:    if i in p.text[:3]:        if '。' in p.text:            p.text = p.text.replace('。''')        if '?' in p.text:            p.text = p.text.replace('?''')        if ':' in p.text:            p.text = p.text.replace(':''')        if ';' in p.text:            p.text = p.text.replace(';''')        return "level1"     else:        continue
  • 二级标题
index2_list = ["(一)""(二)""(三)""(四)""(五)""(六)""(七)""(八)""(九)""(十)""(十一)""(十二)""(十三)""(十四)""(十五)""(十六)""(十七)""(十八)""(十九)""(二十)"]for i in index2_list:    if i in p.text[:4]:        if '。' in p.text:            p.text = p.text.replace('。''')        if '?' in p.text:            p.text = p.text.replace('?''')        if ':' in p.text:            p.text = p.text.replace(':''')        if ';' in p.text:            p.text = p.text.replace(';''')        return "level2"    else:        continue
  • 替换文字(符号)
def replace(p):    """ 替换函数 """    # 替换符号    if '(' in p.text:        p.text = p.text.replace('(''(')    if ')' in p.text:        p.text = p.text.replace(')'')')    if ',' in p.text:        p.text = p.text.replace(','',')    if ':' in p.text:        p.text = p.text.replace(':'':')    if ';' in p.text:        p.text = p.text.replace(';'';')    if '?' in p.text:        p.text = p.text.replace('?''?')    if '》、' in p.text:        p.text = p.text.replace('》、''》')    if '.' in p.text:  # U+ff0e        p.text = p.text.replace('.''.')    if ' ' in p.text:  # 空格        p.text = p.text.replace(' ''')    if ' ' in p.text:  # U+3000        p.text = p.text.replace(' ''')    if ' ' in p.text:  # U+2003        p.text = p.text.replace(' ''')    return p
  • 判断是否是数字(字母)

def isNumberOrLetter(char):    """ 判断是否为数字或字母 """    number_and_letter_strs = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'    if char in number_and_letter_strs:        return "num_or_let"    else:        return False
  • 段落函数

def paragraphFun(is_title, p):    """ 段落函数 """    try:        p.paragraph_format.element.pPr.ind.set(qn("w:leftChars"), '0')  # 左侧缩进        p.paragraph_format.element.pPr.ind.set(qn("w:rightChars"), '0')  # 右侧缩进        p.paragraph_format.element.pPr.ind.set(qn("w:left"), '0')  # 缩进(cm)        p.paragraph_format.element.pPr.ind.set(qn("w:right"), '0')  # 缩进(cm)    except Exception as e:        pass        # print('错误:', e, f'\t{p.text} 不支持设置缩进')    if is_title == "title":        p.alignment = WD_ALIGN_PARAGRAPH.CENTER        p.paragraph_format.line_spacing = Pt(TITLEMARGIN)  # 行距        p.paragraph_format.first_line_indent = None        p.paragraph_format.space_before = Pt(0)        p.paragraph_format.space_after = Pt(0)    elif is_title == "odd_footer":        p.alignment = WD_PARAGRAPH_ALIGNMENT.RIGHT        p.paragraph_format.right_indent = Pt(14)        p.paragraph_format.line_spacing = Pt(TEXTMARGIN)    elif is_title == "even_footer":        p.alignment = WD_PARAGRAPH_ALIGNMENT.LEFT        p.paragraph_format.left_indent = Pt(14)        p.paragraph_format.line_spacing = Pt(TEXTMARGIN)    else:        p.alignment = WD_ALIGN_PARAGRAPH.JUSTIFY        p.paragraph_format.line_spacing = Pt(TEXTMARGIN)  # 行距        p.paragraph_format.space_before = Pt(0)        p.paragraph_format.space_after = Pt(0)        p.paragraph_format.widow_control = False
  • 图片输出
def pic_fix(docx, file, output_path):    """ 图片处理 """    img_path = output_path + "\image"    file_name = path.splitext(file)[0]    parts = docx.part.related_parts    parts_values = parts.values()    parts_keys = parts.keys()    list_val = list(parts_values)    list_key = list(parts_keys)    parts_length = len(parts_values)    if parts_length > 5:        # print(type(list(parts_values)[-1]))        k = 0    for i in range(parts_length):        # print(type(list_val[i]))        if 'image' in str(type(list_val[i])):            if not path.isdir(img_path):                    makedirs(img_path)            # print('找到图片数据')            k += 1            try:                img_data = parts[list_key[i]].image.blob                img_type = parts[list_key[i]].image.ext                full_path = f'{img_path}\{file_name}_image{k}.{img_type}'                print(f"··>提示<·· 正在输出:{full_path}")                with open(full_path, 'wb'as f:                    f.write(img_data)            except:                print(f"··>错误<·· 图片{k}输出失败!")    if k == 0:        print(f"··>提示<·· 未找到图片!")
  • 页边距
def margin(docx):""" 设置页边距 """    for s in docx.sections:        s.top_margin = Cm(PAGETOPMARGIN)        s.bottom_margin = Cm(PAGEBOTTOMMARGIN)        s.left_margin = Cm(PAGELEFTMARGIN)        s.right_margin = Cm(PAGERIGHTMARGIN)
  • 设置奇偶数页不同
# 奇偶页不同docx.settings.odd_and_even_pages_header_footer = True
  • 添加页码
def footer(docx):    """ 设置页脚,添加页码 """    # print(len(docx.sections))    def AddFooterNumber(p):        t1 = p.add_run("— ")        font = t1.font        font.name = PAGENUMBERFONT        font.size = Pt(PAGENUMBERFONTSIZE)  # 14号字体        t1._element.rPr.rFonts.set(qn("w:eastAsia"), PAGENUMBERFONT)        run1 = p.add_run('')        fldChar1 = OxmlElement('w:fldChar')  # creates a new element        fldChar1.set(qn('w:fldCharType'), 'begin')  # sets attribute on element        run1._element.append(fldChar1)        run2 = p.add_run('')        instrText = OxmlElement('w:instrText')        instrText.set(qn('xml:space'), 'preserve')  # sets attribute on element        instrText.text = 'PAGE'        font = run2.font        font.name = PAGENUMBERFONT        font.size = Pt(PAGENUMBERFONTSIZE)  # 14号字体        run2._element.rPr.rFonts.set(qn("w:eastAsia"), PAGENUMBERFONT)        run2._element.append(instrText)        run3 = p.add_run('')        fldChar2 = OxmlElement('w:fldChar')        fldChar2.set(qn('w:fldCharType'), 'end')        run3._element.append(fldChar2)        t2 = p.add_run(" —")        font = t2.font        font.name = PAGENUMBERFONT        font.size = Pt(PAGENUMBERFONTSIZE)  # 14号字体        t2._element.rPr.rFonts.set(qn("w:eastAsia"), PAGENUMBERFONT)    for s in docx.sections:        # print(s.footer)        footer = s.footer  # 获取第一个节的页脚        footer.is_linked_to_previous = True# 编号续前一节        paragraph = footer.paragraphs[0]  # 获取页脚的第一个段落        paragraphFun("odd_footer", paragraph)        AddFooterNumber(paragraph)        even_footer = s.even_page_footer  # 获取第一个节的页脚        even_footer.is_linked_to_previous = True# 编号续前一节        paragraph = even_footer.paragraphs[0]  # 获取页脚的第一个段落        paragraphFun("even_footer", paragraph)        AddFooterNumber(paragraph)
  • 输入路径

def inputPath():    """ 输入路径 """    input_path = type_radio_value.get()    if input_path == "file_path":        file_path = filedialog.askopenfile(title="请选择文件", filetypes=[("docx文件""*.docx")])        if file_path != None:            path_label["text"] = file_path.name    elif input_path == "dir_path":        dir_path = filedialog.askdirectory(title="请选择文件夹")        if dir_path != "":            path_label["text"] = dir_path
  • 入口函数
def main():    """ 主函数 """    if checkPath():        merge_button.config(state="disabled", cursor="wait", text="正在处理")        reset_button.config(state="disabled")        merge_button.update()        reset_button.update()        input_path = path_entry.get().replace("/""\\")        version_ipt = version_radio_value.get()        file_type = type_radio_value.get()        time_ipt = time_radio_value.get()        page_ipt = page_radio_value.get()        img_ipt = img_radio_value.get()        if file_type == "dir_path":            output_path = input_path + "\output"            have_docx = 0            done_list = []            for file in listdir(input_path):                if '~' in file:                    continue                elif file.endswith('.docx'):                    if not path.isdir(output_path):                        makedirs(output_path)                    have_docx += 1                    file_path = path.join(input_path, file)                    save_time, is_done = fixWord(file_path, file, output_path, time_ipt, page_ipt, img_ipt, version_ipt)                    if is_done:                        done_list.append(file_path)            if have_docx == 0:                print("··>错误<·· 没有找到.docx文件")                messagebox.showwarning("警告""没有找到.docx文件!")            else:                if len(done_list) == have_docx:                    messagebox.showinfo("提示", f"全部处理完成!\n共 {have_docx} 个文件\n输出路径:" + output_path)                else:                    messagebox.showinfo("提示", f"处理完成!\n共 {have_docx} 个文件,成功 {len(done_list)} 个,失败 {have_docx - len(done_list)} 个\n输出路径:" + output_path)        elif file_type == "file_path":            # 文件名            file = input_path.split("\\")[-1]            # 输出路径            dir_path = input_path.split("\\")            dir_path.pop()            result = '\\'.join(str(x) for x in dir_path)            output_path = result + "\output"            if not path.isdir(output_path):                makedirs(output_path)            save_time, is_done = fixWord(input_path, file, output_path, time_ipt, page_ipt, img_ipt, version_ipt)            if is_done:                messagebox.showinfo("提示""处理完成!\n输出路径:" + output_path + "\\" + file.split(".")[0] + save_time + ".docx")
  • 功能整合
def fixWord(docx_path, file, output_path, time_ipt, page_ipt, img_ipt, version_ipt):    """ 文档处理 """    docx = Document(docx_path)    # 页边距    margin(docx)    # 修改格式    fixDocx(docx, version_ipt)    # 添加时间后缀    file_name = path.splitext(file)[0]    if time_ipt == "1":        save_time = strftime("%m%d%H%M", localtime())        save_path = output_path + f"\{file_name}" + save_time + ".docx"    else:        save_time = ""        save_path = output_path + f"\{file_name}" + ".docx"    # 设置页码    if page_ipt == "1":        # 奇偶页不同        docx.settings.odd_and_even_pages_header_footer = True        footer(docx)    # 保存文档中的图片    if img_ipt == "1":        picFix(docx, file, output_path)    # 保存文档    output_time = strftime("%m-%d %H:%M:%S", localtime())    try:        docx.save(save_path)        output_txt = output_time + "    " + save_path        play_history_frm_listbox.insert(END, output_txt)        play_history_frm_listbox.update()        # print(f"··>提示<·· 已保存:{output_txt}")        # 设置滚动条位置到最大值,即拖动到最底部        play_history_frm_listbox.yview_moveto(1)        return save_time, True    except PermissionError:        output_txt = output_time + "    " + f"{file_name} 保存失败!文件已打开,请关闭后重试!"        play_history_frm_listbox.insert(END, output_txt)        play_history_frm_listbox.update()        play_history_frm_listbox.yview_moveto(1)        messagebox.showerror("错误"f"{file_name} 保存失败!文件已打开,请关闭后重试!")        return save_time, False
保存为 fix_word.py 文件。
四、py文件打包成可执行文件(.exe文件)
pyinstaller -D -w fix_word.py -n fixWord_v4.3.5 -i icon.ico
pyinstaller详情:https://blog.csdn.net/weixin_43804047/article/details/119704965

→访问主页1(推荐):https://gitee.com/cxmStudio/fixWord
→访问主页2:https://github.com/Sam-CXM/fixWord

## 项目简介

fixWord是一个基于python开发的Word文档修复工具,能够自动修复Word文档中的常见错误,如拼写错误、格式错误等。

## 开发环境

 Python 3.10.7

 python-docx 1.2.0

 pyinstaller 6.14.2

## 项目特点

 支持多种常见错误修复,如拼写错误、格式错误等。

 支持自定义错误类型和修复规则。

 支持单文件和批量修复多个Word文档。

 支持自定义输出结果格式。

## 运行环境

系统
内存 磁盘

Windows10及以上版本

至少2GB

至少75MB

## 使用说明

1.下载地址1(推荐):https://gitee.com/cxmStudio/fixWord/releases/download/v4.3.5/fixWord_v4.3.5.zip

下载地址2:https://github.com/Sam-CXM/fixWord/releases/download/v4.3.5/fixWord_v4.3.5.zip

2.将安装包解压到本地

3.运行fixWord_v4.3.5.exe`文件,点击【文件选项或【文件夹】选项,或输入含有文档的路径

4. 点击【开始处理按钮等待处理完成即可。

5. 处理完成后,会提示输出路径信息。

## 更新日志:

– 维护日期:2026.2.28
    – 【新增】右键输出日志可直接打开文件或文件夹;
    – 【新增】复制路径功能;
    – 【新增】批量处理时成功文件个数提示;
    – 【修复】识别各级标题的逻辑;
    – 【修复】保存出错的问题提示;
    – 【优化】处理文档过程中的按钮状态;
    – 【优化】实时更新输出日志。
    – 【优化】正文处理函数。

 维护日期:2025.6.17  全新4.0版本

 新增】支持用户手动输入路径,输入类型多样化;

新增】底部版本信息;

新增】全角空格替换;

新增】左侧缩进为0(不是首行缩进);

新增】段前段后为0;

新增】取消孤行控制;

优化】界面排版优化,视觉效果更佳;

优化】去掉控制台显示;

优化】本地项目可直接运行;

修复】两位数字后为顿号(、)时,会丢失相邻数之前的数字;

修复】其他问题。

– 维护日期2025.5.6

    – 新增字体常量,便于统一;

    – 新增两个版本:学校留存;上交上报;

    – 新增当前格式显示;

 优化】其他内容;

    – 修复】弹窗的路径不准确的情况。

维护日期:2024.8.21

 【优化】解决了首行缩进 2 字符的问题;

 【优化】设置基础信息常量。

 维护日期:2024.3.12

 【修复】解决了批量处理时选项需要重复输入的问题。

 维护日期:2024.1.22

 【修复】解决了含有图片的文档处理后图片被删除的问题。

 维护日期:2024.1.21

 【新增】可选项判断;

 【新增】处理完成后倒计时自动关闭;

 【优化】图片输出逻辑。

## 注意事项

 本程序仅处理 `.docx` 类型的文件;

 本程序暂不支持处理含有表格内容的文件;

 含有图片的文档图片导出后可能会被压缩;

 本程序无法处理图片格式,如果图片独立成段,本程序所用API识别到图片会被默认是空段落。为了防止图片删除,只能放弃处理空段落及图片格式;

为了处理效果,处理前请将全文`清除全部格式`,操作步骤:`全选`->`开始`->`样式`->`清除格式`;将文档中所有图片环绕文字改为`嵌入型`,操作步骤:`选中图片`->`图片格式`->`排列`->`环绕文字`->`嵌入型`;

 本程序已开源,可免费使用。

项目截图

持续维护中…

本站文章均为手工撰写未经允许谢绝转载:夜雨聆风 » fixWord!升级!全新D版本来袭!

评论 抢沙发

6 + 2 =
  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
×
订阅图标按钮