用 Apache POI 替换 XSLFTextRun 中的单词

Replace a word in a XSLFTextRun with Apache POI

我正在使用 Apache POI 修改 pptx。我试图替换 XSLFTextShape 中的一个词,同时保持 XSLFTextShape 中其他词的格式。

到目前为止我尝试的是以下内容:

private static void replaceText(XSLFTextShape textShape, String marker, String newText){
        textShape.setText(textShape.getText().replace(marker, newText));
    }

这是在替换我想要的词,但同一 XSLFTextShape 中其他词的格式已更改。例如:如果我在同一个 XSLFTextShape 中有一个红色的单词,即使我没有更改这个单词中的任何内容,该单词的颜色也会更改为黑色。

因此我尝试替换 XSLFTextRun 中的单词。这是我写的代码:

    private static void replaceText(XSLFTextShape textShape, String marker, String newText){

        List<XSLFTextParagraph> textParagraphList = textShape.getTextParagraphs();
        textParagraphList.forEach(textParagraph -> {
            List<XSLFTextRun> textRunList = textParagraph.getTextRuns();
            textRunList.forEach(textRun -> {
                if(textRun.getRawText().contains(marker)){
                    textRun.setText(textRun.getRawText().replace(marker, newText));
                }
            });
        });
        //String text = textShape.getText();
        //textShape.setText(textShape.getText().replace(marker, newText));
        //String text2 = textShape.getText();
    }

我在 运行 这段代码时没有收到任何错误,但是这个词没有被替换,我真的不明白为什么。 如果我添加 textShape.setText(textShape.getText().replace(marker, newText)); 行,它会被替换。但是在调试时,我看到 textShape.getText() 在这一行前后给出了相同的结果。

感谢您的帮助!

下一个示例工作:

private static void replace(XSLFTextParagraph paragraph, String searchValue, String replacement) {
    List<XSLFTextRun> textRuns = paragraph.getTextRuns();
    for (XSLFTextRun textRun : textRuns) {
        if (hasReplaceableItem(textRun.getRawText(), searchValue)) {
            String replacedText = StringUtils.replace(textRun.getRawText(), searchValue, replacement);
            textRun.setText(replacedText);
            break;
        }
    }
}
    
private static boolean hasReplaceableItem(String runText, String searchValue) {
   return StringUtils.contains(runText, searchValue);
}

比如我用的:

  • org.apache.poi:poi-ooxml:5.0.0
  • org.apache.commons:commons-lang3:3.9

前后图片:

好的,所以我通过一个(不是很好的)解决方法让它工作: 我正在保存每个段落的文本和样式,删除形状中的文本,然后添加带有文本(包括样式)的新段落。这是代码:

private static void replaceTextButKeepStyle(XSLFTextShape textShape, final String marker, final String text) {
    List<XSLFTextParagraph> textParagraphList = textShape.getTextParagraphs();
    ArrayList<ArrayList<TextAndStyle>> textAndStylesTable = new ArrayList<>();

    for (int i = 0; i < textParagraphList.size(); i++) {
        ArrayList<TextAndStyle> textAndStylesParagraph = new ArrayList<>();

        XSLFTextParagraph textParagraph = textParagraphList.get(i);

        List<XSLFTextRun> textRunList = textParagraph.getTextRuns();

        for (Iterator it2 = textRunList.iterator(); it2.hasNext(); ) {
            Object object = it2.next();
            XSLFTextRun textRun = (XSLFTextRun) object;

            //get Color:
            PaintStyle.SolidPaint solidPaint = (PaintStyle.SolidPaint) textRun.getFontColor(); 
            int color = solidPaint.getSolidColor().getColor().getRGB();

            //save text & styles:
            TextAndStyle textAndStyle = new TextAndStyle(textRun.getRawText(), textRun.isBold(),
                    color, textRun.getFontSize());

            //replace text if marker:
            if (textAndStyle.getText().contains(marker)) {
                textAndStyle.setText(textAndStyle.getText().replace(marker, text));
            }

            textAndStylesParagraph.add(textAndStyle);
        }
        textAndStylesTable.add(textAndStylesParagraph);
    }

    //delete text and add new text with correct styles:
    textShape.clearText();
    textAndStylesTable.forEach(textAndStyles -> {
        XSLFTextParagraph textParagraph = textShape.addNewTextParagraph();
        textAndStyles.forEach(textAndStyle -> {
            TextRun newTextrun = textParagraph.addNewTextRun();
            newTextrun.setText(textAndStyle.getText());
            newTextrun.setFontColor(new Color(textAndStyle.getColorRgb()));
            newTextrun.setBold(textAndStyle.isBold());
            newTextrun.setFontSize(textAndStyle.getFontsize());
        });
    });
}