Как искать и заменять слово / текст в текстовом документе, используя python-docx - PullRequest
1 голос
/ 30 мая 2019

Например: Пожалуйста, найдите ниже параграфы в текстовом документе. Абзацы находятся внутри таблицы.

  1. Хорошо, ребята, пожалуйста, вставайте
  2. Хорошо, ребята, пожалуйста, вставайте.

Я пытаюсь заменить "get" на "wake". Я ищу «get» для замены на «wake» только в случае пункта 1. Но в приведенном ниже коде его получение заменяется в обоих пунктах, как показано в результате ниже. Такое поведение одинаково для всех абзацев в текстовом документе. Пожалуйста предложите работать согласно вышеуказанному требованию.

Фактический результат: 1. Хорошо, ребята, пожалуйста, проснитесь. 2. Хорошо, ребята, пожалуйста, просыпайтесь.

doc = docx.Document("path/docss.docx")
def Search_replace_text():
 for table in doc.tables:
  for row in table.rows:
   for cell in row.cells:
    for paragraph in cell.paragraphs:
     for run in paragraph.runs:
       if str(word.get()) in run.text:
         text = run.text.split(str(word.get())) # Gets input from GUI
         if text[1] == " ":
            run.text = text[0] + str(replace.get()) # Gets input from GUI
            print(run.text)
        else:
            run.text = text[0] + str(replace.get()) + text[1]
     else: break
     doc.save("docss.docx")

Я хочу получить результат, показанный ниже:

  1. Хорошо, ребята, пожалуйста, проснитесь.

  2. Хорошо, ребята, пожалуйста, вставайте.

Фактический результат:

  1. Хорошо, ребята, пожалуйста, проснитесь.

  2. Хорошо, ребята, пожалуйста, просыпайтесь.

Ответы [ 2 ]

0 голосов
/ 26 июня 2019

Проблема с заменой текста в сериях состоит в том, что текст может разбиваться на несколько серий, что означает, что простой поиск и замена текста не всегда будут работать.

Адаптация моего ответа к Python docx Replaceстрока в абзаце с сохранением стиля

Текст, подлежащий замене, может быть разбит на несколько прогонов, поэтому его необходимо искать путем частичного сопоставления, определить, какие прогоны необходимо заменить, а затем заменить текст в идентифицированных.

Эта функция заменяет строки и сохраняет оригинальный стиль текста.Этот процесс одинаков, независимо от того, требуется ли сохранение стиля, поскольку именно стиль может привести к тому, что текст может быть разбит на несколько прогонов, даже если текст визуально не имеет стиля.

Код

import docx


def docx_find_replace_text(doc, search_text, replace_text):
    paragraphs = list(doc.paragraphs)
    for t in doc.tables:
        for row in t.rows:
            for cell in row.cells:
                for paragraph in cell.paragraphs:
                    paragraphs.append(paragraph)
    for p in paragraphs:
        if search_text in p.text:
            inline = p.runs
            # Replace strings and retain the same style.
            # The text to be replaced can be split over several runs so
            # search through, identify which runs need to have text replaced
            # then replace the text in those identified
            started = False
            search_index = 0
            # found_runs is a list of (inline index, index of match, length of match)
            found_runs = list()
            found_all = False
            replace_done = False
            for i in range(len(inline)):

                # case 1: found in single run so short circuit the replace
                if search_text in inline[i].text and not started:
                    found_runs.append((i, inline[i].text.find(search_text), len(search_text)))
                    text = inline[i].text.replace(search_text, str(replace_text))
                    inline[i].text = text
                    replace_done = True
                    found_all = True
                    break

                if search_text[search_index] not in inline[i].text and not started:
                    # keep looking ...
                    continue

                # case 2: search for partial text, find first run
                if search_text[search_index] in inline[i].text and inline[i].text[-1] in search_text and not started:
                    # check sequence
                    start_index = inline[i].text.find(search_text[search_index])
                    check_length = len(inline[i].text)
                    for text_index in range(start_index, check_length):
                        if inline[i].text[text_index] != search_text[search_index]:
                            # no match so must be false positive
                            break
                    if search_index == 0:
                        started = True
                    chars_found = check_length - start_index
                    search_index += chars_found
                    found_runs.append((i, start_index, chars_found))
                    if search_index != len(search_text):
                        continue
                    else:
                        # found all chars in search_text
                        found_all = True
                        break

                # case 2: search for partial text, find subsequent run
                if search_text[search_index] in inline[i].text and started and not found_all:
                    # check sequence
                    chars_found = 0
                    check_length = len(inline[i].text)
                    for text_index in range(0, check_length):
                        if inline[i].text[text_index] == search_text[search_index]:
                            search_index += 1
                            chars_found += 1
                        else:
                            break
                    # no match so must be end
                    found_runs.append((i, 0, chars_found))
                    if search_index == len(search_text):
                        found_all = True
                        break

            if found_all and not replace_done:
                for i, item in enumerate(found_runs):
                    index, start, length = [t for t in item]
                    if i == 0:
                        text = inline[index].text.replace(inline[index].text[start:start + length], str(replace_text))
                        inline[index].text = text
                    else:
                        text = inline[index].text.replace(inline[index].text[start:start + length], '')
                        inline[index].text = text
            # print(p.text)


# sample usage as per example 

doc = docx.Document('find_replace_test_document.docx')
docx_find_replace_text(doc, 'Testing1', 'Test ')
docx_find_replace_text(doc, 'Testing2', 'Test ')
docx_find_replace_text(doc, 'rest', 'TEST')
doc.save('find_replace_test_result.docx')

Пример вывода

Вот несколько снимков экрана, на которых показан исходный документ и результат после замены текста:

'Testing1' -> 'Test '
'Testing2' -> 'Test '
'rest' -> 'TEST'

Исходный документ:

Source document

Результирующий документ:

Resultant document

Надеюсь, это кому-нибудь поможет.

0 голосов
/ 30 мая 2019

заменить

if str(word.get()) in run.text:

с небольшим форматированием

if ' {} '.format(str(word.get())) in run.text:

для поиска в отдельном слове (с двумя пробелами).

...