apachepoi:${my\u placeholder}被视为三个不同的运行

bogh5gae  于 2021-06-30  发布在  Java
关注(0)|答案(1)|浏览(340)

我有一个.docx模板,其中包含要填充的占位符,例如 ${programming_language} , ${education} 等等。
占位符关键字必须很容易与其他普通单词区分开来,因此它们用括号括起来 ${ } .

for (XWPFTable table : doc.getTables()) {
  for (XWPFTableRow row : table.getRows()) {
    for (XWPFTableCell cell : row.getTableCells()) {
      for (XWPFParagraph paragraph : cell.getParagraphs()) {
        for (XWPFRun run : paragraph.getRuns()) {
          System.out.println("run text: " + run.text());
          /**replace text here, etc. */
        }
      }
    }
  }
}

我想把占位符和附件一起提取出来 ${ } 角色。问题是,这似乎是封闭字符被视为不同的运行。。。

run text: ${
run text: programming_language
run text: }
run text: Some plain text here 
run text: ${
run text: education
run text: }

相反,我希望达到以下效果:

run text: ${programming_language}
run text: Some plain text here
run text: ${education}

我尝试过使用其他封闭字符,例如: { } , < > , # # 等等。
我不想做一些奇怪的连接 runs ,等等。我想把它放在一个xwpfrun中。
如果我找不到合适的解决办法,我就这样做: VAR_PROGRAMMING_LANGUGE , VAR_EDUCATION ,我想。

vd8tlhqk

vd8tlhqk1#

当前 apache poi 4.1.2 提供textsegment来处理这些 Word 文本运行问题。searchtext在段落中搜索字符串并返回 TextSegment . 这提供了对该段落中文本的开始和结束运行的访问( BeginRun 以及 EndRun ). 它还提供对begin run中的起始字符位置和end run中的结束字符位置的访问( BeginChar 以及 EndChar ). 它还提供对文本运行中文本元素索引的访问( BeginText 以及 EndText ). 这总是应该的 0 ,因为默认文本运行只有一个文本元素。
有了这个,我们可以做以下工作:
替换在begin run中找到的部分字符串。为此,获取位于搜索字符串之前的文本部分,并将替换内容连接到该字符串。之后,begin run将完全包含替换。
删除开始运行和结束运行之间的所有文本运行,因为它们包含搜索字符串中不再需要的部分。
在结束运行时,只保留搜索字符串后的文本部分。
这样我们就可以替换多个文本运行中的文本。
下面的示例显示了这一点。

import java.io.*;
import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;

public class WordReplaceTextSegment {

 static public void replaceTextSegment(XWPFParagraph paragraph, String textToFind, String replacement) {
  TextSegment foundTextSegment = null;
  PositionInParagraph startPos = new PositionInParagraph(0, 0, 0);
  while((foundTextSegment = paragraph.searchText(textToFind, startPos)) != null) { // search all text segments having text to find

System.out.println(foundTextSegment.getBeginRun()+":"+foundTextSegment.getBeginText()+":"+foundTextSegment.getBeginChar());
System.out.println(foundTextSegment.getEndRun()+":"+foundTextSegment.getEndText()+":"+foundTextSegment.getEndChar());

   // maybe there is text before textToFind in begin run
   XWPFRun beginRun = paragraph.getRuns().get(foundTextSegment.getBeginRun());
   String textInBeginRun = beginRun.getText(foundTextSegment.getBeginText());
   String textBefore = textInBeginRun.substring(0, foundTextSegment.getBeginChar()); // we only need the text before

   // maybe there is text after textToFind in end run
   XWPFRun endRun = paragraph.getRuns().get(foundTextSegment.getEndRun());
   String textInEndRun = endRun.getText(foundTextSegment.getEndText());
   String textAfter = textInEndRun.substring(foundTextSegment.getEndChar() + 1); // we only need the text after

   if (foundTextSegment.getEndRun() == foundTextSegment.getBeginRun()) { 
    textInBeginRun = textBefore + replacement + textAfter; // if we have only one run, we need the text before, then the replacement, then the text after in that run
   } else {
    textInBeginRun = textBefore + replacement; // else we need the text before followed by the replacement in begin run
    endRun.setText(textAfter, foundTextSegment.getEndText()); // and the text after in end run
   }

   beginRun.setText(textInBeginRun, foundTextSegment.getBeginText());

   // runs between begin run and end run needs to be removed
   for (int runBetween = foundTextSegment.getEndRun() - 1; runBetween > foundTextSegment.getBeginRun(); runBetween--) {
    paragraph.removeRun(runBetween); // remove not needed runs
   }

  }
 }

 public static void main(String[] args) throws Exception {

  XWPFDocument doc = new XWPFDocument(new FileInputStream("source.docx"));

  String textToFind = "${This is the text to find}"; // might be in different runs
  String replacement = "Replacement text";

  for (XWPFParagraph paragraph : doc.getParagraphs()) { //go through all paragraphs
   if (paragraph.getText().contains(textToFind)) { // paragraph contains text to find
    replaceTextSegment(paragraph, textToFind, replacement);
   }
  }

  FileOutputStream out = new FileOutputStream("result.docx");
  doc.write(out);
  out.close();
  doc.close();

 }
}

相关问题