Package: python-docx-replace
python-docx-replaceThis library was built on top ofpython-docxand the main purpose is to replace words inside a documentwithout losing the format.There is also a functionality that allows defining blocks in the Word document and set if they will be removed or not.Replacing a word - docx_replaceYou can define a key in your Word document and set the value to be replaced. This program requires the following key format:${key_name}Let's explain the process behind the library:First way, losing formattingOne of the ways to replace a key inside a document is by doing something like the code below. Can you do this? YES! But you are going to lose all the paragraph formatting.key="${name}"value="Ivan"forpinget_all_paragraphs(doc):ifkeyinp.text:p.text=p.text.replace(key,value)Second way, not all keysUsing the python-docx library, each paragraph has a couple ofrunswhich is a proxy for objects wrapping<w:r>element. We are going to tell more about it later and you can see more detailsin the python-docx docs.You can try replacing the text inside the runs and if it works, then your job is done:key="${name}"value="Ivan"forpinget_all_paragraphs(doc):forruninp.runs:ifkeyinrun.text:run.text=run.text.replace(key,value)The problem here is that the key can be broken in more than one run, and then you won't be able to replace it, for example:It's going to work:WordParagraph:"Hello${name}, welcome!"Run1:"Hello${name}, w"Run2:"elcome!"It's NOT going to work:WordParagraph:"Hello${name}, welcome!"Run1:"Hello${na"Run2: "me}, welcome!"You are probably wondering, why does it break paragraph text this way? What are the purpose of therun?Imagine a Word document with this format:Eachrunholds their own format! That's the goal for theruns.Considering this and using this library, what would be the format after parsing the key? Highlighted yellow? Bold and underline? Red with another font? All of them?The final format will be the format that is presentin the $ character. All of the others key's characters and their formats will be discarded. In the example above, the final format will behighlighted yellow.SolutionThe solution adopted is quite simple. First we try to replace in the simplest way, as in the previous example. If it's work, great, all done! If it's not, we build a table of indexes:key="${name}"value="Ivan"WordParagraph:"Hello${name}, welcome!"Run1:"Hello${na"Run2: "me}, welcome!"WordParagraph:'H''e''l''l''o'' ''$''{''n''a''m''e''}'','' ''w''e''l''c''o''m''e''!'CharIndexes:012345678910111213141516171819202122RunIndex:00000000001111111111111RunCharIndex:01234567890123456789101112Herewehavethecharindexes,theindexofeachrunbycharindexandtheruncharindexbyrun.Alittleconfusing,right?Withthistablewecanprocessandreplaceallthekeys,gettingtheresult:# REPLACE PROCESS:CharIndex6=p.runs[0].text="Ivan"# replace '$' by the valueCharIndex7=p.runs[0].text=""# clean all the others partsCharIndex8=p.runs[0].text=""CharIndex9=p.runs[0].text=""CharIndex10=p.runs[1].text=""CharIndex11=p.runs[1].text=""CharIndex12=p.runs[1].text=""After that, we are going to have:WordParagraph:'H''e''l''l''o'' ''Ivan'''''''''''''','' ''w''e''l''c''o''m''e''!'Indexes:012345678910111213141516171819202122RunIndex:00000000001111111111111RunCharIndex:01234567890123456789101112All done, now you Word document is fully replaced keeping all the format.Get document keys - docx_get_keysYou can get all the keys present in the Word document by calling the functiondocx_get_keys:keys=docx_get_keys(doc)# Let's suppose the Word document has the keys: ${name} and ${phone}print(keys)# ['name', 'phone']Replace blocks - docx_blocksYou can define a block in your Word document and set if it is going to be removed or not. The format required for key blocks are exactly like tagsHTML, as following:Initial of block:<signature>End of the block:</signature>Let's say you define two blocks like this:Word document:Contract

Detaisofthecontract

<signature>
Please,putyoursignaturehere:_________________
</signature>Setting signature to be removeddocx_blocks(doc,signature=True)Final Word document:Contract

Detaisofthecontract


Please,putyoursignaturehere:_________________Setting signature to not be removeddocx_blocks(doc,signature=False)Final Word document:Contract

Detaisofthecontractdocx_blocks limitationIf there aretablesinside a block that is set to be removed, these tables are not going to be removed. Tables are different objects in python-docx library and they are not present in the paragraph object.You can use the functiondocx_remove_tableto remove tables from the Word document by their index.docx_remove_table(doc,0)The table index works exactly like any indexing property. It means if you remove an index, it will affect the other indexes. For example, if you want to remove the first two tables, you can't do like this:docx_remove_table(doc,0)docx_remove_table(doc,1)# it will raise an index errorYou should instead do like this:docx_remove_table(doc,0)docx_remove_table(doc,0)How to installVia PyPIpip3installpython-docx-replaceHow to usefrompython_docx_replaceimportdocx_replace# get your document using python-docxdoc=Document("document.docx")# call the replace function with your key value pairsdocx_replace(doc,name="Ivan",phone="+55123456789")# call the blocks function with your setsdocx_blocks(doc,signature=True,table_of_contents=False)# remove the first table in the Word documentdocx_remove_table(doc,0)# do whatever you want after that, usually save the documentdoc.save("replaced.docx")TIP: If you want to call with a defineddictvariable, you can leverage the**syntax from python:my_dict={"name":"Ivan","phone":"+55123456789"}docx_replace(doc,**my_dict)