Jak używać python-docx, aby zastąpić tekst w dokumencie Word i zapisać

Wspomniany na tej samej stronie moduł oodocx odsyła użytkownika do folderu / examples, którego tam nie ma.
Przeczytałem dokumentację Pythona-docx 0.7.2, plus wszystko, co mogłem znaleźć w Stackoverflow na ten temat, więc proszę wierzyć, że odrobiłem swoją "pracę domową".

Python jest jedynym językiem, który znam (początkujący+, może średniozaawansowany), więc proszę nie zakładać żadnej znajomości C, Unix, xml, itp.

Zadanie: otwarcie dokumentu ms-word 2007+ za pomocą jednego linijka tekstu w nim (aby wszystko było proste) i zamień dowolne słowo "kluczowe" w słowniku, które występuje w tej linijce tekstu na jego wartość słownikową. Następnie zamknij dokument, zachowując wszystko inne bez zmian.

Linijka tekstu (na przykład) " pozostaniemy w komnatach morza."

from docx import Document

document = Document('/Users/umityalcin/Desktop/Test.docx')

Dictionary = {‘sea’: “ocean”}

sections = document.sections
for section in sections:
    print(section.start_type)

#Now, I would like to navigate, focus on, get to, whatever to the section that has my
#single line of text and execute a find/replace using the dictionary above.
#then save the document in the usual way.

document.save('/Users/umityalcin/Desktop/Test.docx')

Nie widzę w dokumentacji niczego, co by mi na to pozwalało-może tam jest, ale tego nie rozumiem, bo wszystko nie jest napisane na moim poziomie.

Podążałem za innymi sugestie na tej stronie i starali się korzystać z wcześniejszych wersji modułu ( https://github.com/mikemaccana/python-docx), który powinien mieć "metody jak replace, advReplace" w następujący sposób: otwieram kod źródłowy w interpreterze Pythona i dodaję na końcu następujący tekst (aby uniknąć kolizji z już zainstalowaną wersją 0.7.2):

document = opendocx('/Users/umityalcin/Desktop/Test.docx')
words = document.xpath('//w:r', namespaces=document.nsmap)
for word in words:
    if word in Dictionary.keys():
        print "found it", Dictionary[word]
        document = replace(document, word, Dictionary[word])
savedocx(document, coreprops, appprops, contenttypes, websettings,
    wordrelationships, output, imagefiledict=None) 

Uruchomienie tego powoduje następujący komunikat o błędzie:

NameError: nazwa 'coreprops' nie jest zdefiniowana

Może staram się zrobić coś, czego nie da się zrobić-ale byłbym wdzięczny za pomoc, jeśli brakuje mi czegoś prostego.

Jeśli to ma znaczenie, używam 64 bitowej wersji Canopy Enthought na OSX 10.9.3

Author: Deduplicator, 2014-07-17

4 answers

Obecna wersja Pythona-docx nie posiada funkcji search() ani funkcji replace(). Są one wymagane dość często, ale wdrożenie w ogólnym przypadku jest dość trudne i nie wzrosło jeszcze do góry zaległości.

Kilku ludzi odniosło sukces, robiąc to, czego potrzebują, korzystając z istniejących już urządzeń. Oto przykład. Przy okazji nie ma to nic wspólnego z sekcjami:)

for paragraph in document.paragraphs:
    if 'sea' in paragraph.text:
        print paragraph.text
        paragraph.text = 'new text containing ocean'

Aby wyszukiwać również w tabelach, należy użyć coś w stylu:

for table in document.tables:
    for cell in table.cells:
        for paragraph in cell.paragraphs:
            if 'sea' in paragraph.text:
               ...

Jeśli podążasz tą ścieżką, prawdopodobnie szybko odkryjesz, czym są zawiłości. Jeśli zastąpisz cały tekst akapitu, usuniesz formatowanie na poziomie znaków, takie jak słowo lub fraza pogrubiona lub kursywa.

Przy okazji, kod z odpowiedzi @wnnmaw jest dla starszej wersji Pythona-docx i w ogóle nie będzie działał z wersjami po 0.3.0.

 19
Author: scanny,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-04 09:29:07

Potrzebowałem czegoś do zastąpienia wyrażeń regularnych w docx. Wziąłem scannys odpowiedź. Do obsługi stylu użyłem odpowiedzi z: Python docx zastępuje ciąg znaków w akapicie zachowując styl dodano rekurencyjne wywołanie do obsługi zagnieżdżonych tabel. i wymyśliłem coś takiego:

import re
from docx import Document

def docx_replace_regex(doc_obj, regex , replace):

    for p in doc_obj.paragraphs:
        if regex.search(p.text):
            inline = p.runs
            # Loop added to work with runs (strings with same style)
            for i in range(len(inline)):
                if regex.search(inline[i].text):
                    text = regex.sub(replace, inline[i].text)
                    inline[i].text = text

    for table in doc_obj.tables:
        for row in table.rows:
            for cell in row.cells:
                docx_replace_regex(cell, regex , replace)



regex1 = re.compile(r"your regex")
replace1 = r"your replace string"
filename = "test.docx"
doc = Document(filename)
docx_replace_regex(doc, regex1 , replace1)
doc.save('result1.docx')

Do iteracji nad słownikiem:

for word, replacement in dictionary.items():
    word_re=re.compile(word)
    docx_replace_regex(doc, word_re , replacement)

Zauważ, że to rozwiązanie zastąpi Wyrażenie regularne tylko wtedy, gdy całe wyrażenie regularne ma ten sam styl w dokumencie.

Również jeśli tekst jest edytowany po zapisaniu tego samego stylu tekst może być w oddzielnych biegach. Na przykład, jeśli otworzysz dokument, który ma ciąg "testabcd" i zmienisz go na "test1abcd" i zapisz, nawet ciasto jego ten sam styl są 3 oddzielne biegi "test", " 1 "i " abcd", w tym przypadku wymiana test1 nie będzie działać.

Służy do śledzenia zmian w dokumencie. Aby to zrobić, w Wordzie musisz przejść do "opcji", "Trust Center", a w "opcjach Prywatności" przechowywać losowe liczby, aby poprawić dokładność połączenia " i zapisać dokument.

 8
Author: szum,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:46:57

Problem z drugą próbą polega na tym, że nie zdefiniowałeś parametrów, których potrzebujesz savedocx. Musisz zrobić coś takiego przed zapisujesz:

relationships = docx.relationshiplist()
title = "Document Title"
subject = "Document Subject"
creator = "Document Creator"
keywords = []

coreprops = docx.coreproperties(title=title, subject=subject, creator=creator,
                       keywords=keywords)
app = docx.appproperties()
content = docx.contenttypes()
web = docx.websettings()
word = docx.wordrelationships(relationships)
output = r"path\to\where\you\want\to\save"
 0
Author: wnnmaw,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-17 14:16:02

Office Dev Centre ma wpis, w którym deweloper opublikował (na licencji MIT w tym czasie) opis kilku algorytmów, które wydają się sugerować rozwiązanie tego problemu (choć w C# i wymagają portowania): "MS Dev Centre posting

 0
Author: Soferio,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-21 23:22:57