POI操作Word模板文本替换(表格文本替换)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了POI操作Word模板文本替换(表格文本替换)相关的知识,希望对你有一定的参考价值。

参考技术A

(19条消息) 使用POI读写word docx文件 wangxintong_1992的博客-CSDN博客 poi 写入word

POI操作word模板并生成新的word - (jianshu.com)

POI在读写 word docx 文件时是通过 XWPF 模块来进行的,其核心是XWPFDocument。一个XWPFDocument代表一个docx文档,其可以用来读docx文档,也可以用来写docx文档。XWPFDocument中主要包含下面这几种对象:

XWPFDocument:代表一个docx文档

XWPFParagraph:代表一个段落。

XWPFRun:代表具有相同属性的一段文本。

XWPFTable:代表一个表格。

XWPFTableRow:表格的一行。

XWPFTableCell:表格对应的一个单元格。

如有错误,欢迎指正

替换Apache POI XWPF中的文本

我刚刚发现Apache POI库对于使用Java编辑Word文件非常有用。具体来说,我想使用Apache POI的XWPF类编辑DOCX文件。我发现没有适当的方法/文档,我可以这样做。有人可以分步说明,如何替换DOCX文件中的一些文本。

**文本可以在行/段落或表格行/列中

提前致谢 :)

答案

你需要的方法是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"));
另一答案

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

但是,在段落级别进行替换需要付出代价;你丢失了该段落中的运行格式。例如,如果在段落的中间你加粗了“bits”这个单词,那么在解析文件时你用“bytes”替换了“bits”这个单词,“bytes”这个单词将不再是粗体。因为粗体存储了一个在段落的整个文本体被替换时被删除的运行。附加的代码有一个注释掉的部分,如果需要,它可以在运行级别替换文本。

还应注意,如果要插入的文本包含 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, "
");

    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, "
");
//      
//      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;
//  }
另一答案

我的任务是用单词docx文档中的地图值替换格式$ {key}的文本。上述解决方案是一个很好的起点,但未考虑所有情况:$ {key}不仅可以在多个运行中传播,还可以在运行中的多个文本中传播。因此,我最终得到以下代码:

    private void replace(String inFile, Map<String, String> data, OutputStream out) throws Exception, IOException {
    XWPFDocument doc = new XWPFDocument(OPCPackage.open(inFile));
    for (XWPFParagraph p : doc.getParagraphs()) {
        replace2(p, data);
    }
    for (XWPFTable tbl : doc.getTables()) {
        for (XWPFTableRow row : tbl.getRows()) {
            for (XWPFTableCell cell : row.getTableCells()) {
                for (XWPFParagraph p : cell.getParagraphs()) {
                    replace2(p, data);
                }
            }
        }
    }
    doc.write(out);
}

private void replace2(XWPFParagraph p, Map<String, String> data) {
    String pText = p.getText(); // complete paragraph as string
    if (pText.contains("${")) { // if paragraph does not include our pattern, ignore
        TreeMap<Integer, XWPFRun> posRuns = getPosToRuns(p);
        Pattern pat = Pattern.compile("\$\{(.+?)\}");
        Matcher m = pat.matcher(pText);
        while (m.find()) { // for all patterns in the paragraph
            String g = m.group(1);  // extract key start and end pos
            int s = m.start(1);
            int e = m.end(1);
            String key = g;
            String x = data.get(key);
            if (x == null)
                x = "";
            SortedMap<Integer, XWPFRun> range = posRuns.subMap(s - 2, true, e + 1, true); // get runs which contain the pattern
            boolean found1 = false; // found $
            boolean found2 = false; // found {
            boolean found3 = false; // found }
            XWPFRun prevRun = null; // previous run handled in the loop
            XWPFRun found2Run = null; // run in which { was found
      

以上是关于POI操作Word模板文本替换(表格文本替换)的主要内容,如果未能解决你的问题,请参考以下文章

Apache POI Excel - 搜索和替换文本

vscode 替换选中区域的文本

POI导出word

如何用Python来进行查询和替换一个文本字符串

word文档中如何替换图片

Java Word中的文本图片替换功能