批量docx文件内文本替换

import sys
import os
from collections import OrderedDict
from docx import Document
import win32com.client

# https://zhuanlan.zhihu.com/p/317074324,Python自动化办公之Word,全网最全看这一篇就够了


def print_help():
    print(f'''shell命令模式下用法:
        docx_replace.exe replace docx_dir src_word1 tgt_word2 src_word2 tgt_word2 ...
        docx_replace.exe convert doc_dir
        docx_replace.exe replace docx文件的所在目录 被替换词1 替换词1 被替换词2 替换词2 ...
        docx_replace.exe convert doc文件的所在目录''')

try:
    print_help()
    print('***********************************')
    program_wd=os.path.dirname(os.path.realpath(sys.argv[0]))
    print("程序工作目录:",program_wd)
    print('开始处理配置')
    if len(sys.argv)>=2:
        op_name=sys.argv[1]
        assert len(sys.argv)>=3,'shell命令模式下,请给出docx文件的所在目录'
        wd=sys.argv[2]# working directory,程序进行处理时的工作目录是docx文件的所在目录
        replace_d=OrderedDict()
        if op_name=='replace':
            for i in range(3,len(sys.argv),2):
                replace_d[sys.argv[i]]=sys.argv[i+1]
    else:
        op_name=None
        if os.path.exists('last_wd.txt'):# 如果存在last_wd.txt,读取上一次处理的docx文件位置
            with open('last_wd.txt','r',encoding='utf8') as f:
                wd=f.read()
            if not os.path.exists(wd):
                wd='.'
        else:
            wd='.'
        replace_d=None

    while True:
        op=None
        if op_name is None:
            print('''
        操作及其代号,代号为右括号前边的字符。比如,要替换docx文件里的词语,请在下方>>>后按1并回车:
        1) 替换docx文件里的词语
        2) 转换doc文件为docx文件
        h) 帮助
        q) 退出
            ''')

            op=input('>>>')
            if op=='q':
                break
            elif op=='h':
                print_help()
                continue
            elif op!='1' and op!='2':
                print('非法操作')
                continue
            wd_answer=input(f'要处理的docx文件是否在{os.path.abspath(wd)}下?若否,请在后面填写新的docx文件目录再回车;若是,请直接回车:')
            if len(wd_answer)>0:
                wd=wd_answer
            while not os.path.exists(wd):
                print(f'**************************{wd}目录并不存在。当前工作目录{program_wd}*******************************\n目录的格式应类似“C:/Users/test”或者“C:\\\\Users\\\\test”')
                wd=program_wd
                wd_answer=input(f'要处理的docx文件是否在{os.path.abspath(wd)}下?若否,请在后面填写新的docx文件目录再回车;若是,请直接回车:')
                if len(wd_answer)>0:
                    wd=wd_answer
            with open('last_wd.txt','w',encoding='utf8') as f:
                f.write(wd)
        print(f'即将处理{os.path.abspath(wd)}下的docx文件')
        os.chdir(wd)
        if op=='1' or op_name=='replace':
            if replace_d is None:
                print('''
        获取替换词和被替换词的操作及其代号,代号为右括号前边的字符。比如,要从replace_dict.txt读取被替换词和替换词的对应关系,请在下方>>>后按1并回车:
        1) 从replace_dict.txt读取被替换词和替换词的对应关系
        2) 持续输入被替换词和替换词直到退出
            ''')
                inp_mode=input('>>>')
                replace_d=OrderedDict()
                if inp_mode=='1':
                    if os.path.exists(f'{program_wd}/replace_dict.txt'):
                        with open(f'{program_wd}/replace_dict.txt','r',encoding='utf8') as f:
                            contents=f.read()
                        for line in contents.strip().split('\n'):
                            if len(line)==0:
                                continue
                            replace_d[line.split(' ')[0]]=line.split(' ')[1]
                    else:
                        print(f'**************************{program_wd}/replace_dict.txt文件并不存在,无法读取被替换词和替换词之间的对应关系*******************************')
                elif inp_mode=='2':
                    while True:
                        src_word=input('被替换词(如果直接回车,则不会记录本次的被替换词和替换词):')
                        tgt_word=input('替换词(如果直接回车,则不会记录本次的被替换词和替换词):')
                        if len(src_word)>0 and len(tgt_word)>0:
                            replace_d[src_word]=tgt_word
                        a=input('继续?(y/n)y继续,n退出:')
                        if a=='n':
                            break
            if len(list(replace_d.keys()))==0:        
                print(f'**************************没有给出被替换词和替换词,无法进行批量替换*******************************')
                continue
            print(f'准备在{wd}目录下对docx中的下列词语进行替换:')
            for src_word in replace_d:
                print(f'{src_word}--->{replace_d[src_word]}')
            if not os.path.exists(f'../docx_replace_{src_word}_{replace_d[src_word]}'):
                os.mkdir(f'../docx_replace_{src_word}_{replace_d[src_word]}')
            files=os.listdir()
            count=0
            for file in files:
                count+=1
                if file.endswith('.docx'):
                    print(f'{count}/{len(files)}   正在替换{file}中的词语,替换后的新docx文件在{os.path.abspath("../docx_replace_"+src_word+"_"+replace_d[src_word])}')
                    document=Document(file)
                    for table in document.tables:
                        for row in table.rows:
                            for cell in row.cells:
                                ss=cell.text # source string
                                for src_word in replace_d:
                                    ss=ss.replace(src_word,replace_d[src_word])
                                cell.text=ss
                    for p in document.paragraphs:
                        # https://www.cnblogs.com/chargeworld/p/11867051.html python 操作 word 图片 消失
                        runt=[]
                        for run in p.runs:
                            if run.text:
                                runt.append(run.text)
                                run.text=''
                        src_text=''.join(runt)
                        for src_word in replace_d:
                            src_text=src_text.replace(src_word,replace_d[src_word])
                            # print(src_text)
                        p.add_run(src_text)
                    document.save(f'../docx_replace_{src_word}_{replace_d[src_word]}/{file}')
        elif op=='2' or op_name=='convert':
            # https://blog.csdn.net/mingupup/article/details/136882759   自己动手做一个批量doc转换为docx文件的小工具
            if not os.path.exists('../doc2docx'):
                os.mkdir('../doc2docx')
            files=os.listdir()
            count=0
            for file in files:
                count+=1
                if file.endswith('.doc'):
                    print(f'{count}/{len(files)}   正在转换:{file}--->{os.path.abspath("../doc2docx/"+file.rsplit(".",1)[0]+".docx")}')
                    word=win32com.client.Dispatch("Word.Application")
                    doc=word.Documents.Open(os.path.abspath(file))
                    doc.SaveAs(os.path.abspath(f'../doc2docx/{file.rsplit(".",1)[0]}.docx'),FileFormat=16)
                    doc.Close()
        if len(sys.argv)>=5 or op_name=='convert': # shell命令模式下不需要循环执行操作
            break
        op_name=None
        replace_d=None
        os.chdir(program_wd)
except Exception as e:
    print(f'出现异常\n{e}')
    input('按任意键继续')

额外说明

本程序没有解决掉word文档一些复杂的底层数据表示,所以,文本替换后的段落的格式与原文件中它所采用的样式的格式保持一致,比如说,原文件中上标和下标采用的样式是“正文”,于是在文本替换后的文档里对应的地方就是正文字体及其大小。(文本替换后的docx文件和原文件的一些地方的格式存在细微差距,大致是这个原因)

请确保docx文件所在目录里只有要替换文本的docx文件,本程序会处理目录下的所有docx文件。

新的docx文件的存储目录的命名格式是“docx_replace_最后一个被替换词_最后一个替换词”。如果多次替换时最后一个被替换词和最后一个替换词都是相同的且不想将多次替换后的docx文件都放在同一个目录里,可以考虑用文档里不会出现的词语作为被替换词来区分开最后生成的目录,比如设置最后一个被替换词和替换词分别是2502021107某公司和123。

python源文件打包成exe文件

pip install pyinstaller; pyinstaller -F -i docx_replace.ico test.py

创建于2502021432,修改于2502021432

posted @ 2025-02-02 17:03  园糯  阅读(91)  评论(0)    收藏  举报