Java 替换 Apache POI XWPF 中的文本不起作用

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24203087/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 10:47:38  来源:igfitidea点击:

Replacing a text in Apache POI XWPF not working

javaapachems-wordapache-poi

提问by Michael

I'm currently trying to work on the code mentioned on a previous post called Replacing a text in Apache POI XWPF.

我目前正在尝试处理上一篇名为Replacing a text in Apache POI XWPF 的帖子中提到的代码。

I have tried the below and it works but I don't know if I am missing anything. When I run the code the text is not replaced but added onto the end of what was searched. For example I have created a basic word document and entered the text "test". In the below code when I run it I eventually get the new document with the text "testDOG".

我已经尝试了下面的方法并且它有效,但我不知道我是否遗漏了什么。当我运行代码时,文本不会被替换,而是添加到搜索内容的末尾。例如,我创建了一个基本的 word 文档并输入了文本“test”。在下面的代码中,当我运行它时,我最终得到了带有文本“testDOG”的新文档。

I have had to change the original code from String text = r.getText(0) to String text = r.toString() because I kept getting a NullError while running the code.

我不得不将原始代码从 String text = r.getText(0) 更改为 String text = r.toString() 因为我在运行代码时不断收到 NullError 。

import java.io.*;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.xwpf.extractor.XWPFWordExtractor;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;


public class testPOI {

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

    String filepath = "F:\MASTER_DOC.docx";
    String outpath = "F:\Test.docx";

    XWPFDocument doc = new XWPFDocument(OPCPackage.open(filepath));
    for (XWPFParagraph p : doc.getParagraphs()){
        for (XWPFRun r : p.getRuns()){
            String text = r.toString();
            if(text.contains("test")) {
                text = text.replace("test", "DOG");
                r.setText(text);
            }
        }
    }
   doc.write(new FileOutputStream(outpath));
}

EDIT: Thanks for your help everyone. I browsed around and found a solution on Replace table column value in Apache POI

编辑:感谢大家的帮助。我浏览了一下,找到了一个关于在 Apache POI 中替换表列值的解决方案

回答by JamesB

Your logic is not quite right. You need to collate all the text in the runs first and then do the replace. You also need to remove all runs for the paragraph and add a new single run if a match on "test" is found.

你的逻辑不太对。您需要先整理运行中的所有文本,然后进行替换。您还需要删除该段落的所有运行,并在找到“测试”匹配项时添加新的单次运行。

Try this instead:

试试这个:

public class testPOI {

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

        String filepath = "F:\MASTER_DOC.docx";
        String outpath = "F:\Test.docx";

        XWPFDocument doc = new XWPFDocument(new FileInputStream(filepath));
        for (XWPFParagraph p : doc.getParagraphs()){

            int numberOfRuns = p.getRuns().size();

            // Collate text of all runs
            StringBuilder sb = new StringBuilder();
            for (XWPFRun r : p.getRuns()){
                int pos = r.getTextPosition();
                if(r.getText(pos) != null) {
                    sb.append(r.getText(pos));
                }
            }

            // Continue if there is text and contains "test"
            if(sb.length() > 0 && sb.toString().contains("test")) {
                // Remove all existing runs
                for(int i = 0; i < numberOfRuns; i++) {
                    p.removeRun(i);
                }
                String text = sb.toString().replace("test", "DOG");
                // Add new run with updated text
                XWPFRun run = p.createRun();
                run.setText(text);
                p.addRun(run);
            }
        }
       doc.write(new FileOutputStream(outpath));
    }
}

回答by Josh

This method replace search Strings in paragraphs and is able to work with Strings spanning over more than one Run.

此方法替换段落中的搜索字符串,并且能够处理跨越多个运行的字符串。

  private long replaceInParagraphs(Map<String, String> replacements, List<XWPFParagraph> xwpfParagraphs) {
    long count = 0;
    for (XWPFParagraph paragraph : xwpfParagraphs) {
      List<XWPFRun> runs = paragraph.getRuns();

      for (Map.Entry<String, String> replPair : replacements.entrySet()) {    
        String find = replPair.getKey();
        String repl = replPair.getValue();
        TextSegement found = paragraph.searchText(find, new PositionInParagraph());
        if ( found != null ) {
          count++;
          if ( found.getBeginRun() == found.getEndRun() ) {
            // whole search string is in one Run
            XWPFRun run = runs.get(found.getBeginRun());
            String runText = run.getText(run.getTextPosition());
            String replaced = runText.replace(find, repl);
            run.setText(replaced, 0);
          } else {
            // The search string spans over more than one Run
            // Put the Strings together
            StringBuilder b = new StringBuilder();
            for (int runPos = found.getBeginRun(); runPos <= found.getEndRun(); runPos++) {
              XWPFRun run = runs.get(runPos);
              b.append(run.getText(run.getTextPosition()));
            }                       
            String connectedRuns = b.toString();
            String replaced = connectedRuns.replace(find, repl);

            // The first Run receives the replaced String of all connected Runs
            XWPFRun partOne = runs.get(found.getBeginRun());
            partOne.setText(replaced, 0);
            // Removing the text in the other Runs.
            for (int runPos = found.getBeginRun()+1; runPos <= found.getEndRun(); runPos++) {
              XWPFRun partNext = runs.get(runPos);
              partNext.setText("", 0);
            }                          
          }
        }
      }      
    }
    return count;
  }

回答by Gor

just change text for every run in your paragraph, and then save the file. this code worked for mi

只需更改段落中每次运行的文本,然后保存文件。此代码适用于 mi

XWPFDocument doc = new XWPFDocument(new FileInputStream(filepath));
for (XWPFParagraph p : doc.getParagraphs()) {
    StringBuilder sb = new StringBuilder();
    for (XWPFRun r : p.getRuns()) {
    String text = r.getText(0);
    if (text != null && text.contains("variable1")) {
        text = text.replace("variable1", "valeur1");
        r.setText(text, 0);
    }
    if (text != null && text.contains("variable2")) {
        text = text.replace("variable2", "valeur2");
        r.setText(text, 0);
    }
    if (text != null && text.contains("variable3")) {
        text = text.replace("variable3", "valeur3");
        r.setText(text, 0);
    }
    }

}

doc.write(new FileOutputStream(outpath));

回答by Jv Shan Belnas

Don't waste your time when you can keep things simple:

当您可以保持简单时,不要浪费时间:

//download from http://www.independentsoft.de/jword/evaluation.htmlimport com.independentsoft.office.word.WordDocument;

//从http://www.independentsoft.de/jword/evaluation.html下载 import com.independentsoft.office.word.WordDocument;

public class JWORD {

公共类 JWORD {

public static void main(String[] args) {

    String filepath = "C:\Users\setrivayne\Downloads\TEST.docx";
    String outpath = "C:\Users\setrivayne\Downloads\TEST.docx";

    try {

         WordDocument doc = new WordDocument(filepath);

         doc.replace("FIRST NAME", "first name");
         doc.replace("MIDDLE NAME", "middle name");
         doc.replace("LAST NAME", "last name");

         doc.save(outpath, true);

     } catch (Exception e) {
         System.out.println(e.getMessage());
         e.printStackTrace();
     }
}

}

}

回答by Gayan Kavirathne

Worth noticing that, run.getPosition()returns -1 most of the cases. But it does not effect when there is only one text postion per a run. But, technically it can have any number of textPositionsand I've experienced such cases. So, the best way is to getCTR ()for run and terate through each the run for count of textPositions. Number of textPositionsare equal to ctrRun.sizeOfTArray()

值得注意的是,run.getPosition()在大多数情况下返回 -1。但是当每次运行只有一个文本位置时,它不起作用。但是,从技术上讲,它可以有任意数量的,textPositions而且我经历过这样的情况。因此,最好的方法是getCTR ()for run 并遍历每个 run for count of textPositions。数量textPositions等于ctrRun.sizeOfTArray()

A sample code

示例代码

for (XWPFRun run : p.getRuns()){
     CTR ctrRun =  run.getCTR();
     int sizeOfCtr = ctrRun.sizeOfTArray();
     for(int textPosition=0; textPosition<sizeOfCtr){
            String text = run.getText(textPosition);
            if(text.contains("test")) {
                 text = text.replace("test", "DOG");
                 r.setText(text,textPosition);
            }
     }

 }