Поиск и замена текста в презентациях PowerPoint на Android

Обзор

Aspose.Slides for Android via Java может искать, выделять и заменять текст в отдельном текстовом фрейме или по всей презентации. Каждая операция также может уведомлять приложение о каждом совпадении через обратный вызов результата. Это позволяет обновлять презентацию и одновременно формировать журнал аудита, содержащий найденный текст, его контекст, позицию, текстовый фрейм и номер слайда.

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

В первых примерах ниже используется файл “sample.pptx”, который содержит один текстовый блок на первом слайде со следующим текстом:

Пример текста

Выбор области поиска

Используйте методы на ITextFrame чтобы ограничить операцию одним текстовым фреймом. Используйте методы на IPresentation чтобы обработать весь применимый текст в презентации.

Операция Один текстовый фрейм Вся презентация
Выделить буквальный текст ITextFrame.highlightText IPresentation.highlightText
Выделить совпадения регулярного выражения ITextFrame.highlightRegex IPresentation.highlightRegex
Заменить буквальный текст ITextFrame.replaceText IPresentation.replaceText
Заменить совпадения регулярного выражения ITextFrame.replaceRegex IPresentation.replaceRegex

Настройка сопоставления текста

Для операций с буквальным текстом используйте TextSearchOptions для управления поиском:

Операции с регулярными выражениями используют Java Pattern, поэтому правила сопоставления, такие как чувствительность к регистру и границы слов, задаются в самом выражении и его флагах.

Сбор информации о совпадениях через обратный вызов

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

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

import com.aspose.slides.*;
import java.util.ArrayList;
import java.util.List;

final class TextMatch {
    private final ITextFrame textFrame;
    private final String sourceText;
    private final String foundText;
    private final int textPosition;
    private final Integer slideNumber;

    TextMatch(ITextFrame textFrame, String sourceText, String foundText, int textPosition, Integer slideNumber) {
        this.textFrame = textFrame;
        this.sourceText = sourceText;
        this.foundText = foundText;
        this.textPosition = textPosition;
        this.slideNumber = slideNumber;
    }

    ITextFrame getTextFrame() {
        return textFrame;
    }

    String getSourceText() {
        return sourceText;
    }

    String getFoundText() {
        return foundText;
    }

    int getTextPosition() {
        return textPosition;
    }

    Integer getSlideNumber() {
        return slideNumber;
    }
}

final class TextSearchCallback implements IFindResultCallback {
    private final List<TextMatch> results = new ArrayList<TextMatch>();

    List<TextMatch> getResults() {
        return results;
    }

    @Override
    public void foundResult(ITextFrame textFrame, String sourceText, String foundText, int textPosition) {
        Integer slideNumber = getSlideNumber(textFrame);
        TextMatch result = new TextMatch(textFrame, sourceText, foundText, textPosition, slideNumber);
        results.add(result);
    }

    private static Integer getSlideNumber(ITextFrame textFrame) {
        if (!(textFrame instanceof TextFrame)) {
            return null;
        }

        IBaseSlide parentSlide = ((TextFrame) textFrame).getSlide();

        if (parentSlide instanceof ISlide) {
            return ((ISlide) parentSlide).getSlideNumber();
        }

        if (parentSlide instanceof INotesSlide) {
            return ((INotesSlide) parentSlide).getParentSlide().getSlideNumber();
        }

        return null;
    }
}

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

Выделение текста

Вызовите метод ITextFrame.highlightText для выделения совпадений буквального текста в текстовом фрейме. Передайте TextSearchOptions для управления поиском и обратный вызов для сбора деталей совпадений.

Пример кода ниже выделяет все вхождения символов “try”, а затем выделяет только полное слово “to”. Оба поиска отправляют свои совпадения в один и тот же обратный вызов.

import com.aspose.slides.*;
import android.graphics.Color;

Presentation presentation = new Presentation("sample.pptx");
try {
    ISlide slide = presentation.getSlides().get_Item(0);
    IAutoShape shape = (IAutoShape) slide.getShapes().get_Item(0);
    TextSearchCallback callback = new TextSearchCallback();

    TextSearchOptions substringSearchOptions = new TextSearchOptions();
    substringSearchOptions.setCaseSensitive(false);
    int substringHighlightColor = Color.rgb(173, 216, 230);

    // Выделить каждое вхождение "try" в текстовом фрейме.
    shape.getTextFrame().highlightText("try", substringHighlightColor, substringSearchOptions, callback);

    TextSearchOptions wholeWordSearchOptions = new TextSearchOptions();
    wholeWordSearchOptions.setWholeWordsOnly(true);
    wholeWordSearchOptions.setCaseSensitive(false);
    int wholeWordHighlightColor = Color.rgb(238, 130, 238);

    // Выделить только полное слово "to".
    shape.getTextFrame().highlightText("to", wholeWordHighlightColor, wholeWordSearchOptions, callback);

    for (TextMatch result : callback.getResults()) {
        System.out.println("Found '" + result.getFoundText() + "' at position " +
                result.getTextPosition() + " on slide " + result.getSlideNumber() + ".");
    }

    presentation.save("highlighted_text.pptx", SaveFormat.Pptx);
} finally {
    presentation.dispose();
}

Результат:

Выделенный текст

Выделение текста с помощью регулярных выражений

Метод ITextFrame.highlightRegex выделяет совпадения, найденные регулярным выражением, в текстовом фрейме.

Следующий код выделяет все слова, содержащие семь и более символов, и собирает каждое совпадение:

import com.aspose.slides.*;
import android.graphics.Color;
import java.util.regex.Pattern;

Presentation presentation = new Presentation("sample.pptx");
try {
    ISlide slide = presentation.getSlides().get_Item(0);
    IAutoShape shape = (IAutoShape) slide.getShapes().get_Item(0);
    TextSearchCallback callback = new TextSearchCallback();
    Pattern regex = Pattern.compile("\\b[^\\s]{7,}\\b");

    shape.getTextFrame().highlightRegex(regex, Color.YELLOW, callback);

    presentation.save("highlighted_text_using_regex.pptx", SaveFormat.Pptx);
} finally {
    presentation.dispose();
}

Результат:

Выделенный текст с использованием регулярного выражения

Выделение текста по всей презентации

Используйте IPresentation.highlightText и IPresentation.highlightRegex для поиска во всех применимых текстовых фреймах презентации. Следующий пример выделяет буквальный термин и все электронные адреса, сохраняя отдельные коллекции результатов для двух поисков.

import com.aspose.slides.*;
import android.graphics.Color;
import java.util.regex.Pattern;

Presentation presentation = new Presentation("presentation.pptx");
try {
    TextSearchCallback termCallback = new TextSearchCallback();
    TextSearchOptions searchOptions = new TextSearchOptions();
    searchOptions.setWholeWordsOnly(true);
    searchOptions.setCaseSensitive(false);

    int termHighlightColor = Color.rgb(255, 165, 0);
    presentation.highlightText("confidential", termHighlightColor, searchOptions, termCallback);

    TextSearchCallback emailCallback = new TextSearchCallback();
    Pattern emailRegex = Pattern.compile(
            "\\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,}\\b",
            Pattern.CASE_INSENSITIVE);

    presentation.highlightRegex(emailRegex, Color.YELLOW, emailCallback);
    presentation.save("highlighted_presentation.pptx", SaveFormat.Pptx);
} finally {
    presentation.dispose();
}

Замена текста в текстовом фрейме

Для буквального текста используйте ITextFrame.replaceText, а для замены по шаблону — ITextFrame.replaceRegex. Эти методы изменяют найденный текст в существующем текстовом фрейме, сохраняя форматирование окружающих участков вместо полной перестройки фрейма из простой строки.

Следующий пример стандартизирует вариант написания слова и затем заменяет метки версии. Один и тот же обратный вызов записывает оригинальные термины, найденные обеими операциями.

import com.aspose.slides.*;
import java.util.regex.Pattern;

Presentation presentation = new Presentation("presentation.pptx");
try {
    ISlide slide = presentation.getSlides().get_Item(0);
    IAutoShape shape = (IAutoShape) slide.getShapes().get_Item(0);
    TextSearchCallback callback = new TextSearchCallback();
    TextSearchOptions searchOptions = new TextSearchOptions();
    searchOptions.setWholeWordsOnly(true);
    searchOptions.setCaseSensitive(false);

    shape.getTextFrame().replaceText("colour", "color", searchOptions, callback);

    Pattern versionRegex = Pattern.compile("\\bv\\d+(?:\\.\\d+)*\\b", Pattern.CASE_INSENSITIVE);
    shape.getTextFrame().replaceRegex(versionRegex, "current version", callback);

    presentation.save("updated_text_frame.pptx", SaveFormat.Pptx);
} finally {
    presentation.dispose();
}

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

Замена текста по всей презентации

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

import com.aspose.slides.*;
import java.util.regex.Pattern;

Presentation presentation = new Presentation("presentation.pptx");
try {
    TextSearchCallback callback = new TextSearchCallback();
    TextSearchOptions searchOptions = new TextSearchOptions();
    searchOptions.setWholeWordsOnly(true);
    searchOptions.setCaseSensitive(true);

    presentation.replaceText("Contoso", "Example Corp", searchOptions, callback);

    Pattern accountNumberRegex = Pattern.compile("\\bACCT-\\d{6}\\b");
    presentation.replaceRegex(accountNumberRegex, "ACCT-REDACTED", callback);

    presentation.save("updated_presentation.pptx", SaveFormat.Pptx);
} finally {
    presentation.dispose();
}

Группировка совпадений для отчётности

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

import com.aspose.slides.ITextFrame;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

Map<Integer, Map<ITextFrame, List<TextMatch>>> matchesBySlide =
        new LinkedHashMap<Integer, Map<ITextFrame, List<TextMatch>>>();

for (TextMatch result : callback.getResults()) {
    Integer slideNumber = result.getSlideNumber();
    Map<ITextFrame, List<TextMatch>> matchesByTextFrame = matchesBySlide.get(slideNumber);

    if (matchesByTextFrame == null) {
        matchesByTextFrame = new LinkedHashMap<ITextFrame, List<TextMatch>>();
        matchesBySlide.put(slideNumber, matchesByTextFrame);
    }

    ITextFrame textFrame = result.getTextFrame();
    List<TextMatch> textFrameMatches = matchesByTextFrame.get(textFrame);

    if (textFrameMatches == null) {
        textFrameMatches = new java.util.ArrayList<TextMatch>();
        matchesByTextFrame.put(textFrame, textFrameMatches);
    }

    textFrameMatches.add(result);
}

for (Map.Entry<Integer, Map<ITextFrame, List<TextMatch>>> slideEntry : matchesBySlide.entrySet()) {
    String slideLabel = slideEntry.getKey() == null ? "Other" : slideEntry.getKey().toString();
    System.out.println("Slide: " + slideLabel);

    for (Map.Entry<ITextFrame, List<TextMatch>> textFrameEntry : slideEntry.getValue().entrySet()) {
        System.out.println("  Text frame: " + textFrameEntry.getKey().getText());

        for (TextMatch result : textFrameEntry.getValue()) {
            System.out.println("    '" + result.getFoundText() + "' at position " +
                    result.getTextPosition() + "; context: '" + result.getSourceText() + "'");
        }
    }
}

FAQ

Как искать только один текстовый блок вместо всей презентации?

Получите текстовый фрейм формы и вызовите ITextFrame.highlightText, ITextFrame.highlightRegex, ITextFrame.replaceText, или ITextFrame.replaceRegex для этого фрейма. Методы уровня презентации обрабатывают все применимые текстовые фреймы.

Как сопоставить полные слова с учётом регистра?

Установите TextSearchOptions.setWholeWordsOnly и TextSearchOptions.setCaseSensitive в true и передайте параметры в метод выделения или замены буквального текста. Для регулярных выражений определите границы слов и чувствительность к регистру непосредственно в Java Pattern.

Можно ли включить в поиск и замену текст из заметок слайдов?

Да. Установите TextSearchOptions.setIncludeNotes в true при использовании буквальной операции на уровне презентации. Реализация обратного вызова, приведённая выше, сопоставляет совпадение в заметке с номером родительского слайда.

Как создать отчёт без повторного сканирования презентации?

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

Сохраняет ли замена текста его форматирование?

ITextFrame.replaceText и ITextFrame.replaceRegex изменяют найденный текст внутри существующего текстового фрейма и сохраняют форматирование окружающих участков. Если совпадение охватывает участки с разным форматированием, проверьте результат, чтобы убедиться, что замена использует желаемый стиль.