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

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

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

  1. for (XWPFTable table : doc.getTables()) {
  2. for (XWPFTableRow row : table.getRows()) {
  3. for (XWPFTableCell cell : row.getTableCells()) {
  4. for (XWPFParagraph paragraph : cell.getParagraphs()) {
  5. for (XWPFRun run : paragraph.getRuns()) {
  6. System.out.println("run text: " + run.text());
  7. /**replace text here, etc. */
  8. }
  9. }
  10. }
  11. }
  12. }

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

  1. run text: ${
  2. run text: programming_language
  3. run text: }
  4. run text: Some plain text here
  5. run text: ${
  6. run text: education
  7. run text: }

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

  1. run text: ${programming_language}
  2. run text: Some plain text here
  3. 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将完全包含替换。
删除开始运行和结束运行之间的所有文本运行,因为它们包含搜索字符串中不再需要的部分。
在结束运行时,只保留搜索字符串后的文本部分。
这样我们就可以替换多个文本运行中的文本。
下面的示例显示了这一点。

  1. import java.io.*;
  2. import org.apache.poi.xwpf.usermodel.*;
  3. import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
  4. public class WordReplaceTextSegment {
  5. static public void replaceTextSegment(XWPFParagraph paragraph, String textToFind, String replacement) {
  6. TextSegment foundTextSegment = null;
  7. PositionInParagraph startPos = new PositionInParagraph(0, 0, 0);
  8. while((foundTextSegment = paragraph.searchText(textToFind, startPos)) != null) { // search all text segments having text to find
  9. System.out.println(foundTextSegment.getBeginRun()+":"+foundTextSegment.getBeginText()+":"+foundTextSegment.getBeginChar());
  10. System.out.println(foundTextSegment.getEndRun()+":"+foundTextSegment.getEndText()+":"+foundTextSegment.getEndChar());
  11. // maybe there is text before textToFind in begin run
  12. XWPFRun beginRun = paragraph.getRuns().get(foundTextSegment.getBeginRun());
  13. String textInBeginRun = beginRun.getText(foundTextSegment.getBeginText());
  14. String textBefore = textInBeginRun.substring(0, foundTextSegment.getBeginChar()); // we only need the text before
  15. // maybe there is text after textToFind in end run
  16. XWPFRun endRun = paragraph.getRuns().get(foundTextSegment.getEndRun());
  17. String textInEndRun = endRun.getText(foundTextSegment.getEndText());
  18. String textAfter = textInEndRun.substring(foundTextSegment.getEndChar() + 1); // we only need the text after
  19. if (foundTextSegment.getEndRun() == foundTextSegment.getBeginRun()) {
  20. 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
  21. } else {
  22. textInBeginRun = textBefore + replacement; // else we need the text before followed by the replacement in begin run
  23. endRun.setText(textAfter, foundTextSegment.getEndText()); // and the text after in end run
  24. }
  25. beginRun.setText(textInBeginRun, foundTextSegment.getBeginText());
  26. // runs between begin run and end run needs to be removed
  27. for (int runBetween = foundTextSegment.getEndRun() - 1; runBetween > foundTextSegment.getBeginRun(); runBetween--) {
  28. paragraph.removeRun(runBetween); // remove not needed runs
  29. }
  30. }
  31. }
  32. public static void main(String[] args) throws Exception {
  33. XWPFDocument doc = new XWPFDocument(new FileInputStream("source.docx"));
  34. String textToFind = "${This is the text to find}"; // might be in different runs
  35. String replacement = "Replacement text";
  36. for (XWPFParagraph paragraph : doc.getParagraphs()) { //go through all paragraphs
  37. if (paragraph.getText().contains(textToFind)) { // paragraph contains text to find
  38. replaceTextSegment(paragraph, textToFind, replacement);
  39. }
  40. }
  41. FileOutputStream out = new FileOutputStream("result.docx");
  42. doc.write(out);
  43. out.close();
  44. doc.close();
  45. }
  46. }
展开查看全部

相关问题