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

Java 替换Apache POI XWPF中的文本不起作用,java,apache,ms-word,apache-poi,Java,Apache,Ms Word,Apache Poi,我目前正试图处理上一篇文章中提到的代码 我试过下面的方法,效果不错,但我不知道我是否遗漏了什么。当我运行代码时,文本不会被替换,而是添加到搜索内容的末尾。例如,我创建了一个基本word文档,并输入了文本“test”。在下面的代码中,当我运行它时,我最终得到了文本为“testDOG”的新文档 我不得不将原始代码从String text=r.getText(0)更改为String text=r.toString(),因为我在运行代码时不断收到一个null错误 import java.io.*; im

我目前正试图处理上一篇文章中提到的代码

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

我不得不将原始代码从String text=r.getText(0)更改为String text=r.toString(),因为我在运行代码时不断收到一个null错误

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));
}

编辑:谢谢大家的帮助。我浏览了一下,在

上找到了一个解决方案。你的逻辑不太正确。您需要首先整理运行中的所有文本,然后进行替换。如果在“测试”中找到匹配项,则还需要删除段落的所有运行,并添加新的单个运行

请尝试以下方法:

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));
    }
}
公共类testPOI{
公共静态void main(字符串[]args)引发异常{
String filepath=“F:\\MASTER\u DOC.docx”;
String outpath=“F:\\Test.docx”;
XWPFDocument doc=newxwpfdocument(newfileinputstream(filepath));
对于(XWPFParagraph p:doc.getparagraph()){
int numberOfRuns=p.getRuns().size();
//整理所有运行的文本
StringBuilder sb=新的StringBuilder();
对于(XWPFRun r:p.getRuns()){
int pos=r.getTextPosition();
if(r.getText(pos)!=null){
sb.append(r.getText(pos));
}
}
//如果有文本且包含“测试”,则继续
如果(sb.length()>0&&sb.toString()包含(“测试”)){
//删除所有现有管路
对于(int i=0;i
此方法替换段落中的搜索字符串,并且能够处理跨越多个运行的字符串

  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;
  }
private long replaceInParagraphs(映射替换、列表xwpfParagraphs){
长计数=0;
对于(xwpfParagraphs段落:xwpfParagraphs){
列表运行=段落.getRuns();
对于(Map.Entry replPair:replacements.entrySet()){
字符串find=replPair.getKey();
字符串repl=replPair.getValue();
TEXTSEGENT found=段落.searchText(查找,新位置paragraph());
如果(找到!=null){
计数++;
if(found.getBeginRun()==found.getEndRun()){
//整个搜索字符串在一次运行中
XWPFRun=runs.get(find.getBeginRun());
字符串runText=run.getText(run.getTextPosition());
String replaced=runText.replace(find,repl);
run.setText(替换为0);
}否则{
//搜索字符串跨越多个运行
//把绳子放在一起
StringBuilder b=新的StringBuilder();

对于(int runPos=found.getBeginRun();runPos,只需更改段落中每次运行的文本,然后保存文件。 此代码适用于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));

当你可以让事情简单化时,不要浪费时间:

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

public class 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();
         }
    }
}

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

示例代码

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);
            }
     }

 }
for(XWPFRun:p.getRuns()){
CTR ctrRun=run.getCTR();
int sizeOfCtr=ctrRun.sizeOfTArray();

对于(int textPosition=0;textPosition什么版本的Apache POI与此一起使用?如果它不是最新版本,您是否尝试过升级?感谢您的回复,我使用的是最新的稳定版本3.10-FINAL。我会尝试一下James的想法。谢谢。它可以工作一点,但不完全工作。例如,如果您使用下面的文本,它不工作,并且格式完全正常错。Jeget lacinia sem commodo ac.Fusce molestie sodales suscipit.Maecenas tortor sem、rutrum vel test eu、elementum fermentum sem。感谢您的帮助,James。我在[link]()上找到了一个解决方案,非常好!将此实现与来自的逻辑结合起来,现在我们有了一种全局搜索和替换的方法:)值得注意的是,
run.getPosition()
在大多数情况下返回-1。但是,当每次运行只有一个文本位置时,它不起作用。但是,从技术上讲,它可以有任意数量的文本位置,我也经历过这种情况。因此,最好的方法是
getCTR()
for run,并通过每次运行计算文本位置数。文本位置数等于
ctrRun.sizeOfTArray()
这是有史以来最好的答案,我从未在internet的其他地方发现过此实现。谢谢