Чем раньше вы выкинете форд из своего инструментария тем вам будет легче!!!
Эта фиговина заменяет ключевые слова в виде ${name} которые находятся в вордовом документе на значения из словаря в файле данных. (точнее это ограниченая версия mako templates).
Такой ход был выбран поскольку надо было работать и с doc и с docx. И собирать ошметки слов очень накладно.
Предупреждаю - эта штука медленная.
Посмотрите внимательно - не код а море заплаток. см. первое предложение поста.
По идее не хватает предопределенных функций для вставки табличных данных.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
u"""
mako templates by win32com in winword
"""
import mako
from mako.lookup import TemplateLookup
from mako.template import Template
from mako.lexer import Lexer
import argparse
import codecs
import os
import re
import win32com.client
from win32com.client import constants as c
import time
import shutil
import yaml
def subst_doc(word,doc,reprule):
word.Selection.HomeKey(c.wdStory)
fnd= word.Selection.Find
fnd.ClearFormatting()
fnd.Forward = True
fnd.Format = False
fnd.MatchCase = False
fnd.MatchWholeWord = False
fnd.MatchWildcards = False
fnd.MatchSoundsLike = False
fnd.MatchAllWordForms = False
for a,b in reprule:
fnd.Text = a.replace(u"\n",u"\r")
fnd.Execute()
e=word.Selection.End
word.Selection.InsertAfter(b.replace(u"\n",u"\r"))
e1=word.Selection.End
word.Selection.End=e
word.Selection.Cut()
# word.Selection.Collapse(c.wdCollapseEnd)
#in_file = u"ref.docx"
#out_file = u"ref1.docx"
#data_file = u"data.yaml"
def convert(in_file, out_file, data_file,show_word=0):
if data_file:
with codecs.open(data_file,"r",encoding='utf-8') as f:
data =yaml.load(f)
else:
data={}
if in_file!=out_file:
if os.path.exists(out_file):
os.remove(out_file)
shutil.copy(in_file,out_file)
word = win32com.client.gencache.EnsureDispatch("Word.Application")
word.Visible = show_word
time.sleep(1)
word.Documents.Open(os.path.abspath(out_file))
doc = word.Documents(word.ActiveDocument())
from win32com.client import constants as c
try:
text_b = doc.Content.Text.replace(u"\r",u"\n")
lk= Lexer(text_b)
text_a = Template(text_b).render(**data)
res=lk.parse()
reprule=[]# что ищем и на что заменяем
i0_b=0
i0_a=0
expr_beg_b=0
expr_beg_a=0
expr_end_b=0
expr_end_a=0
control_count=0
for i in res.nodes:
if type(i) is mako.parsetree.Text:
ct=i.content
# нашли блок текста
pos_b=text_b[i0_b:].find(ct)
pos_a=text_a[i0_a:].find(ct)
pos_b+=i0_b
pos_a+=i0_a
# если мы не внутри циклов то это конец предыдущего выражения
if control_count==0:
expr_end_b=pos_b
expr_end_a=pos_a
# если есть конец то сбрасываем выражения в список
if expr_end_b>expr_beg_b:
reprule.append([text_b[expr_beg_b:expr_end_b],text_a[expr_beg_a:expr_end_a]])
# передвинули стартовую позицию на конец текста
i0_b=pos_b+len(ct)
i0_a=pos_a+len(ct)
if control_count==0:
# ставим начало на конец найденного текста
expr_beg_b=i0_b
expr_beg_a=i0_a
else:
# тут контролирем только вложенность for и if
if type(i) is mako.parsetree.ControlLine:
if i.isend:
control_count-=1
else:
control_count+=1
# если последним был шаблон то добразываем и его
if not type(res.nodes[-1]) is mako.parsetree.Text:
reprule.append([text_b[expr_beg_b:],text_a[expr_beg_a:]])
subst_doc(word,doc,reprule)
doc.Save()
finally:
word.Quit()
if __name__ == '__main__':
parser = argparse.ArgumentParser(prog="word_mako",description="substitute data to word_mako infile outfile")
parser.add_argument("-d","--data",default="",help=u"dile with data")
parser.add_argument("-o","--output", help=u"output file")
parser.add_argument("-w","--word", action='store_true', help=u"output file")
parser.add_argument("file",help=u"input file")
args = parser.parse_args()
convert(args.file, args.output, args.data, show_word=args.word)