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