替换 Apache POI XWPF 中的文本

新手上路,请多包涵

我刚刚发现 Apache POI 库对于使用 Java 编辑 Word 文件非常有用。具体来说,我想使用 Apache POI 的 XWPF 类编辑 DOCX 文件。我没有找到合适的方法/文档来执行此操作。有人可以按步骤解释如何替换 DOCX 文件中的某些文本。

\*\* 文本可能在一行/段落或表格行/列中

提前致谢 :)

原文由 Gagan93 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.6k
2 个回答

您需要的方法是 XWPFRun.setText(String) 。只需按照您的方式浏览文件,直到找到感兴趣的 XWPFRun,计算出您想要的新文本,然后替换它。 (运行是具有相同格式的文本序列)

您应该能够执行以下操作:

 XWPFDocument doc = new XWPFDocument(OPCPackage.open("input.docx"));
for (XWPFParagraph p : doc.getParagraphs()) {
    List<XWPFRun> runs = p.getRuns();
    if (runs != null) {
        for (XWPFRun r : runs) {
            String text = r.getText(0);
            if (text != null && text.contains("needle")) {
                text = text.replace("needle", "haystack");
                r.setText(text, 0);
            }
        }
    }
}
for (XWPFTable tbl : doc.getTables()) {
   for (XWPFTableRow row : tbl.getRows()) {
      for (XWPFTableCell cell : row.getTableCells()) {
         for (XWPFParagraph p : cell.getParagraphs()) {
            for (XWPFRun r : p.getRuns()) {
              String text = r.getText(0);
              if (text != null && text.contains("needle")) {
                text = text.replace("needle", "haystack");
                r.setText(text,0);
              }
            }
         }
      }
   }
}
doc.write(new FileOutputStream("output.docx"));

原文由 Gagravarr 发布,翻译遵循 CC BY-SA 3.0 许可协议

下面是我们使用 Apache POI 进行的文本替换。我们发现替换整个 XWPFParagraph 的文本而不是运行是不值得的,而且更简单。由于 Microsoft Word 负责在文档段落中创建运行的位置,因此运行可以在单词中间随机拆分。因此,您可能正在搜索的文本可能在一次运行中占一半,而在另一次运行中可能占一半。使用段落的全文,删除其现有的运行,并添加具有调整后文本的新运行似乎可以解决文本替换问题。

但是,在段落级别进行替换是有代价的;您丢失了该段落中运行的格式。例如,如果在您的段落中间将“位”一词加粗,然后在解析文件时将“位”一词替换为“字节”,则“字节”一词将不再加粗。因为粗体存储在一个运行中,当段落的整个正文被替换时,该运行被删除。附加的代码有一个注释掉的部分,如果需要,它可以在运行级别替换文本。

还应注意,如果您插入的文本包含 \n 返回字符,则以下内容有效。如果不在返回之前为每个部分创建运行并标记运行 addCarriageReturn(),我们找不到插入返回的方法。干杯

    package com.healthpartners.hcss.client.external.word.replacement;

import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;

public class TextReplacer {
    private String searchValue;
    private String replacement;

    public TextReplacer(String searchValue, String replacement) {
        this.searchValue = searchValue;
        this.replacement = replacement;
    }

    public void replace(XWPFDocument document) {
        List<XWPFParagraph> paragraphs = document.getParagraphs();

    for (XWPFParagraph xwpfParagraph : paragraphs) {
        replace(xwpfParagraph);
    }
}

private void replace(XWPFParagraph paragraph) {
    if (hasReplaceableItem(paragraph.getText())) {
        String replacedText = StringUtils.replace(paragraph.getText(), searchValue, replacement);

        removeAllRuns(paragraph);

        insertReplacementRuns(paragraph, replacedText);
    }
}

private void insertReplacementRuns(XWPFParagraph paragraph, String replacedText) {
    String[] replacementTextSplitOnCarriageReturn = StringUtils.split(replacedText, "\n");

    for (int j = 0; j < replacementTextSplitOnCarriageReturn.length; j++) {
        String part = replacementTextSplitOnCarriageReturn[j];

        XWPFRun newRun = paragraph.insertNewRun(j);
        newRun.setText(part);

        if (j+1 < replacementTextSplitOnCarriageReturn.length) {
            newRun.addCarriageReturn();
        }
    }
}

private void removeAllRuns(XWPFParagraph paragraph) {
    int size = paragraph.getRuns().size();
    for (int i = 0; i < size; i++) {
        paragraph.removeRun(0);
    }
}

private boolean hasReplaceableItem(String runText) {
    return StringUtils.contains(runText, searchValue);
}

//REVISIT The below can be removed if Michele tests and approved the above less versatile replacement version

//  private void replace(XWPFParagraph paragraph) {
//      for (int i = 0; i < paragraph.getRuns().size()  ; i++) {
//          i = replace(paragraph, i);
//      }
//  }

//  private int replace(XWPFParagraph paragraph, int i) {
//      XWPFRun run = paragraph.getRuns().get(i);
//
//      String runText = run.getText(0);
//
//      if (hasReplaceableItem(runText)) {
//          return replace(paragraph, i, run);
//      }
//
//      return i;
//  }

//  private int replace(XWPFParagraph paragraph, int i, XWPFRun run) {
//      String runText = run.getCTR().getTArray(0).getStringValue();
//
//      String beforeSuperLong = StringUtils.substring(runText, 0, runText.indexOf(searchValue));
//
//      String[] replacementTextSplitOnCarriageReturn = StringUtils.split(replacement, "\n");
//
//      String afterSuperLong = StringUtils.substring(runText, runText.indexOf(searchValue) + searchValue.length());
//
//      Counter counter = new Counter(i);
//
//      insertNewRun(paragraph, run, counter, beforeSuperLong);
//
//      for (int j = 0; j < replacementTextSplitOnCarriageReturn.length; j++) {
//          String part = replacementTextSplitOnCarriageReturn[j];
//
//          XWPFRun newRun = insertNewRun(paragraph, run, counter, part);
//
//          if (j+1 < replacementTextSplitOnCarriageReturn.length) {
//              newRun.addCarriageReturn();
//          }
//      }
//
//      insertNewRun(paragraph, run, counter, afterSuperLong);
//
//      paragraph.removeRun(counter.getCount());
//
//      return counter.getCount();
//  }

//  private class Counter {
//      private int i;
//
//      public Counter(int i) {
//          this.i = i;
//      }
//
//      public void increment() {
//          i++;
//      }
//
//      public int getCount() {
//          return i;
//      }
//  }

//  private XWPFRun insertNewRun(XWPFParagraph xwpfParagraph, XWPFRun run, Counter counter, String newText) {
//      XWPFRun newRun = xwpfParagraph.insertNewRun(counter.i);
//      newRun.getCTR().set(run.getCTR());
//      newRun.getCTR().getTArray(0).setStringValue(newText);
//
//      counter.increment();
//
//      return newRun;
//  }

原文由 Kyle Willkomm 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题