在 PHP 中搜索和替换 PowerPoint 演示文稿的文本
概述
Aspose.Slides for PHP via Java 可以在单个文本框或整个演示文稿中搜索、突出显示和替换文本。每个操作还可以通过结果回调通知应用程序每一次匹配。这使得在更新演示文稿的同时能够构建包含匹配文本、其上下文、位置、文本框和幻灯片编号的审计跟踪。
这些功能可用于审阅、编辑、术语检查、模板清理和自动化报告工作流。
在下面的第一个示例中,我们使用名为“sample.pptx”的文件,该文件在第一张幻灯片上包含一个带有以下文本的单个文本框:

选择搜索范围
使用 TextFrame 上的方法将操作限制在一个文本框内。使用 Presentation 上的方法处理演示文稿中所有适用的文本。
| 操作 | 单个文本框 | 整个演示文稿 |
|---|---|---|
| 突出显示文字字面值 | TextFrame::highlightText | Presentation::highlightText |
| 突出显示正则表达式匹配项 | TextFrame::highlightRegex | Presentation::highlightRegex |
| 替换文字字面值 | TextFrame::replaceText | Presentation::replaceText |
| 替换正则表达式匹配项 | TextFrame::replaceRegex | Presentation::replaceRegex |
配置文本匹配
对于文字字面值操作,使用 TextSearchOptions 控制匹配方式:
- TextSearchOptions::setWholeWordsOnly 将匹配限制为完整单词。
- TextSearchOptions::setCaseSensitive 控制是否必须匹配字符大小写。
- TextSearchOptions::setIncludeNotes 在演示文稿级别的搜索、替换和突出显示操作中包含幻灯片备注。
正则表达式操作使用 Java Pattern,因此大小写敏感性和单词边界等匹配规则由表达式及其标志定义。
确定文本框的所有者
通用的文本处理工作流在搜索、替换、验证或导出文本时通常会接收到一个 TextFrame。使用 TextFrame::getParentShape 和 TextFrame::getParentCell 可确定哪个演示文稿对象拥有该文本框。
预期值取决于所有者:
| 文本框所有者 | getParentShape |
getParentCell |
|---|---|---|
| AutoShape 或其他包含文本的形状 | 拥有者 Shape | null |
| 表格单元格 | null |
拥有者 Cell |
两种方法都提供只读导航。调用它们不会移动文本框或更改其所有者。通用代码应使用 java_is_null 检查两个值,并处理两者都不可用的情况。
以下示例使用 SlideUtil::getAllTextFrames 迭代演示文稿中的文本框。对于形状,它报告形状名称、Java 运行时类型和所在幻灯片;对于表格单元格,它报告零基的列行坐标以及所在幻灯片。
use aspose\slides\Presentation;
use aspose\slides\SlideUtil;
$presentation = new Presentation("presentation.pptx");
$arrayClass = new java_class("java.lang.reflect.Array");
try {
$textFrames = SlideUtil::getAllTextFrames($presentation, false);
$textFrameCount = java_values($arrayClass->getLength($textFrames));
for ($textFrameIndex = 0; $textFrameIndex < $textFrameCount; $textFrameIndex++) {
$textFrame = $textFrames[$textFrameIndex];
$ownerShape = $textFrame->getParentShape();
if (!java_is_null($ownerShape)) {
$shapeName = java_values($ownerShape->getName());
$shapeName = $shapeName === "" ? "(unnamed)" : $shapeName;
$shapeType = java_values($ownerShape->getClass()->getSimpleName());
$baseSlide = $ownerShape->getSlide();
$slideClassName = java_values($baseSlide->getClass()->getName());
if ($slideClassName === "com.aspose.slides.Slide") {
$slideLabel = "slide " . java_values($baseSlide->getSlideNumber());
} elseif ($slideClassName === "com.aspose.slides.NotesSlide") {
$slideLabel = "notes for slide " . java_values($baseSlide->getParentSlide()->getSlideNumber());
} else {
$slideLabel = java_values($baseSlide->getClass()->getSimpleName());
}
echo("Shape: " . $shapeName . "; type: " . $shapeType . "; " . $slideLabel . "\n");
continue;
}
$ownerCell = $textFrame->getParentCell();
if (!java_is_null($ownerCell)) {
$baseSlide = $ownerCell->getSlide();
$slideClassName = java_values($baseSlide->getClass()->getName());
if ($slideClassName === "com.aspose.slides.Slide") {
$slideLabel = "slide " . java_values($baseSlide->getSlideNumber());
} elseif ($slideClassName === "com.aspose.slides.NotesSlide") {
$slideLabel = "notes for slide " . java_values($baseSlide->getParentSlide()->getSlideNumber());
} else {
$slideLabel = java_values($baseSlide->getClass()->getSimpleName());
}
echo("Table cell: column " . java_values($ownerCell->getFirstColumnIndex()) . ", row " . java_values($ownerCell->getFirstRowIndex()) . "; " . $slideLabel . "\n");
continue;
}
echo("The text frame owner is not available as a shape or table cell.\n");
}
} finally {
$presentation->dispose();
}
对于 SmartArt 内容,遍历 SmartArtNode::getShapes 中的形状,并访问每个 SmartArtShape::getTextFrame。文本框可通过 TextFrame::getParentShape 追溯到其关联的形状,而 TextFrame::getParentCell 返回 null。因此,示例中的形状分支也处理来自 SmartArt 节点的文本。
使用回调收集匹配信息
向突出显示或替换方法传递 Java 代理回调,以便在每次匹配时接收通知。回调方法接收相关的文本框、源文本、匹配文本以及匹配位置。
回调不会直接接收幻灯片编号。下面的实现从父幻灯片中推导出编号,并且还能处理幻灯片备注中的文本。结果数组在文本关联到其他幻灯片类型时使用 null。
class TextSearchCallback {
private $results = [];
public function getResults() {
return $this->results;
}
public function foundResult($textFrame, $sourceText, $foundText, $textPosition) {
$slideNumber = $this->getSlideNumber($textFrame);
$this->results[] = [
"textFrame" => $textFrame,
"sourceText" => java_values($sourceText),
"foundText" => java_values($foundText),
"textPosition" => java_values($textPosition),
"slideNumber" => $slideNumber
];
}
private function getSlideNumber($textFrame) {
$parentShape = $textFrame->getParentShape();
$parentCell = $textFrame->getParentCell();
if (!java_is_null($parentShape)) {
$parentSlide = $parentShape->getSlide();
} elseif (!java_is_null($parentCell)) {
$parentSlide = $parentCell->getSlide();
} else {
$parentSlide = $textFrame->getSlide();
}
if (java_is_null($parentSlide)) {
return null;
}
$parentSlideClass = $parentSlide->getClass();
$classNameValue = $parentSlideClass->getName();
$className = java_values($classNameValue);
if ($className === "com.aspose.slides.Slide") {
$slideNumber = $parentSlide->getSlideNumber();
return java_values($slideNumber);
}
if ($className === "com.aspose.slides.NotesSlide") {
$slide = $parentSlide->getParentSlide();
$slideNumber = $slide->getSlideNumber();
return java_values($slideNumber);
}
return null;
}
}
在将该 PHP 对象传递给操作之前为其创建代理:
$callbackHandler = new TextSearchCallback();
$callbackInterface = java("com.aspose.slides.IFindResultCallback");
$callback = java_closure(
$callbackHandler,
null,
$callbackInterface
);
对于替换操作,foundText 包含原始匹配文本,因此回调可以准确记录被替换的词语。
突出显示文本
使用 TextFrame::highlightText 方法在文本框中突出显示文字字面值匹配项。传入 TextSearchOptions 以控制搜索。
下面的代码示例首先突出显示所有出现的 “try”,然后仅突出显示完整单词 “to”。
$presentation = new Presentation("sample.pptx");
try {
$slide = $presentation->getSlides()->get_Item(0);
$shape = $slide->getShapes()->get_Item(0);
$callbackHandler = new TextSearchCallback();
$callbackInterface = java("com.aspose.slides.IFindResultCallback");
$callback = java_closure(
$callbackHandler,
null,
$callbackInterface
);
$substringSearchOptions = new TextSearchOptions();
$substringSearchOptions->setCaseSensitive(false);
$substringHighlightColor = new Java("java.awt.Color", 173, 216, 230);
// 在文本框中突出显示所有出现的 "try"。
$shape->getTextFrame()->highlightText(
"try",
$substringHighlightColor,
$substringSearchOptions,
$callback
);
$wholeWordSearchOptions = new TextSearchOptions();
$wholeWordSearchOptions->setWholeWordsOnly(true);
$wholeWordSearchOptions->setCaseSensitive(false);
$wholeWordHighlightColor = new Java("java.awt.Color", 238, 130, 238);
// 仅突出显示完整单词 "to"。
$shape->getTextFrame()->highlightText(
"to",
$wholeWordHighlightColor,
$wholeWordSearchOptions,
$callback
);
foreach ($callbackHandler->getResults() as $result) {
echo(
"Found '" . $result["foundText"] . "' at position " .
$result["textPosition"] . " on slide " .
$result["slideNumber"] . ".\n"
);
}
$presentation->save("highlighted_text.pptx", SaveFormat::Pptx);
}
finally {
$presentation->dispose();
}
结果:

使用正则表达式突出显示文本
TextFrame::highlightRegex 方法在文本框中突出显示正则表达式找到的匹配文本。
下面的代码突出显示所有包含七个或更多字符的单词:
$presentation = new Presentation("sample.pptx");
try {
$slide = $presentation->getSlides()->get_Item(0);
$shape = $slide->getShapes()->get_Item(0);
$regex = java("java.util.regex.Pattern")->compile("\\b[^\\s]{7,}\\b");
$highlightColor = java("java.awt.Color")->YELLOW;
$shape->getTextFrame()->highlightRegex($regex, $highlightColor, null);
$presentation->save("highlighted_text_using_regex.pptx", SaveFormat::Pptx);
}
finally {
$presentation->dispose();
}
结果:

跨演示文稿突出显示文本
使用 Presentation::highlightText 和 Presentation::highlightRegex 在演示文稿中搜索所有适用的文本框。下面的示例突出显示一个文字字面值和所有电子邮件地址:
$presentation = new Presentation("presentation.pptx");
try {
$searchOptions = new TextSearchOptions();
$searchOptions->setWholeWordsOnly(true);
$searchOptions->setCaseSensitive(false);
$termHighlightColor = java("java.awt.Color")->ORANGE;
$presentation->highlightText(
"confidential",
$termHighlightColor,
$searchOptions,
null
);
$patternClass = java("java.util.regex.Pattern");
$emailPattern = "\\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,}\\b";
$emailRegex = $patternClass->compile(
$emailPattern,
$patternClass->CASE_INSENSITIVE
);
$emailHighlightColor = java("java.awt.Color")->YELLOW;
$presentation->highlightRegex($emailRegex, $emailHighlightColor, null);
$presentation->save("highlighted_presentation.pptx", SaveFormat::Pptx);
}
finally {
$presentation->dispose();
}
在文本框中替换文本
使用 TextFrame::replaceText 进行文字字面值替换,使用 TextFrame::replaceRegex 进行基于模式的替换。这些方法在现有文本框内更新匹配文本,保留周围部分的格式,而不是从纯字符串重新构建文本框。
下面的示例先统一一种拼写变体,然后替换版本标签:
$presentation = new Presentation("presentation.pptx");
try {
$slide = $presentation->getSlides()->get_Item(0);
$shape = $slide->getShapes()->get_Item(0);
$searchOptions = new TextSearchOptions();
$searchOptions->setWholeWordsOnly(true);
$searchOptions->setCaseSensitive(false);
$shape->getTextFrame()->replaceText(
"colour",
"color",
$searchOptions,
null
);
$patternClass = java("java.util.regex.Pattern");
$versionPattern = "\\bv\\d+(?:\\.\\d+)*\\b";
$versionRegex = $patternClass->compile(
$versionPattern,
$patternClass->CASE_INSENSITIVE
);
$shape->getTextFrame()->replaceRegex(
$versionRegex,
"current version",
null
);
$presentation->save("updated_text_frame.pptx", SaveFormat::Pptx);
}
finally {
$presentation->dispose();
}
如果一次匹配跨越不同格式的部分,请检查输出以确认替换文本应采用哪种格式。
跨演示文稿替换文本
使用 Presentation::replaceText 和 Presentation::replaceRegex 在整个演示文稿中应用相同操作。这对于模板清理、术语更新和编辑非常有用。
$presentation = new Presentation("presentation.pptx");
try {
$searchOptions = new TextSearchOptions();
$searchOptions->setWholeWordsOnly(true);
$searchOptions->setCaseSensitive(true);
$presentation->replaceText(
"Contoso",
"Example Corp",
$searchOptions,
null
);
$accountNumberRegex = java("java.util.regex.Pattern")->compile(
"\\bACCT-\\d{6}\\b"
);
$presentation->replaceRegex(
$accountNumberRegex,
"ACCT-REDACTED",
null
);
$presentation->save("updated_presentation.pptx", SaveFormat::Pptx);
}
finally {
$presentation->dispose();
}
将匹配项分组用于报告
因为每个结果都存储了幻灯片编号和文本框,应用程序可以将匹配项按审计、报告或审阅工作流分组。下面的示例先按幻灯片再按文本框对收集的结果进行分组:
$matchesBySlide = [];
$systemClass = java("java.lang.System");
foreach ($callbackHandler->getResults() as $result) {
$slideNumber = $result["slideNumber"];
$slideLabel = $slideNumber === null ? "Other" : (string) $slideNumber;
$textFrame = $result["textFrame"];
$textFrameHash = $systemClass->identityHashCode($textFrame);
$textFrameKey = (string) java_values($textFrameHash);
if (!isset($matchesBySlide[$slideLabel])) {
$matchesBySlide[$slideLabel] = [];
}
if (!isset($matchesBySlide[$slideLabel][$textFrameKey])) {
$matchesBySlide[$slideLabel][$textFrameKey] = [
"textFrame" => $textFrame,
"matches" => []
];
}
$matchesBySlide[$slideLabel][$textFrameKey]["matches"][] = $result;
}
foreach ($matchesBySlide as $slideLabel => $textFrameGroups) {
echo("Slide: " . $slideLabel . "\n");
foreach ($textFrameGroups as $textFrameGroup) {
$textFrame = $textFrameGroup["textFrame"];
echo(" Text frame: " . $textFrame->getText() . "\n");
foreach ($textFrameGroup["matches"] as $result) {
echo(
" '" . $result["foundText"] . "' at position " .
$result["textPosition"] . "; context: '" .
$result["sourceText"] . "'\n"
);
}
}
}
常见问题
如何只搜索单个文本框而不是整个演示文稿?
获取形状的文本框,然后在该文本框上调用 TextFrame::highlightText、TextFrame::highlightRegex、TextFrame::replaceText 或 TextFrame::replaceRegex。演示文稿级别的方法会处理所有适用的文本框。
如何匹配完整单词并保持正确的大小写?
将 TextSearchOptions::setWholeWordsOnly 和 TextSearchOptions::setCaseSensitive 设置为 true,并将选项传递给文字字面值的突出显示或替换方法。对于正则表达式,在 Java Pattern 本身中定义单词边界和大小写敏感性。
搜索和替换可以包含幻灯片备注中的文本吗?
可以。使用演示文稿级别的文字字面值操作时,将 TextSearchOptions::setIncludeNotes 设置为 true。
如何在不二次扫描演示文稿的情况下生成报告?
向突出显示或替换操作传递 Java 代理回调。它在操作运行期间接收每一次匹配,应用程序可以存储源文本、匹配文本、位置、文本框以及推导出的幻灯片编号,以便后续分组或导出。
替换文本时是否保留其格式?
TextFrame::replaceText 和 TextFrame::replaceRegex 在现有文本框内修改匹配文本并保留周围部分的格式。如果匹配跨越不同格式的段落,请检查结果以确保替换使用所需的样式。