使用Java Apache POI从docx文件中的特定单词中更改字体样式

问题描述

我正在使用Apache POI XWPF来操作docx文件,我需要更新一些段落文字并更改其字体样式。要更新一个单词,可以,假设我的docx内容具有以下段落:

Lorem ipsum dolor坐着,安全奉献精英。 Integer pretium soDales nisl,ut ornare ligula vehicula vitae。 Fusce non magna feugiat,马萨诸塞州马萨诸塞州,发酵罐。 Curabitur auctor leo vitae 学期,促进功能性前庭。毛里斯痣 sem,编号venenatis arcu congue id。 Duis nulla quam,Commodore Vel Dolor eget,颞部静脉曲张。佩莱恩特斯克孕妇 t,智人秘诀,非咒语性外阴 性爱色情。麦格纳斯(Magna Nunc)的梅塞纳斯(Maecenas)。

Nulla sagittis aliquam maximus。 Cras faucibus id是need sed faucibus。紫茎泽兰等植物中的原发性前庭 溃疡性小疮菜豆发酵菌 最大内翻。 Pellentesque du lorem,卢克图斯·非洛雷姆a,布兰迪特 拉希尼亚阿库。 Nunc porttitor erat ut elit hendrerit malesuada。塞得 礼拜堂,rutrum est ut,vulputate orci。悬念直径 ullamcorper,个人简历,feugiat前。在习惯中 高原苦酒。每个类别的许可 根据历史的概念委内瑞拉Proin Massa lectus e.fassilla a niss.fastilla molestie nisl。

我只是做类似的事情,在这种情况下,代码有效,我只想将单词“ ipsum”更新为“ hello world”:

   File file = new File("document.docx");
   FileInputStream fis = new FileInputStream(file.getAbsolutePath());

   XWPFDocument document = new XWPFDocument(fis);

   List<XWPFParagraph> paragraphs = document.getParagraphs();

    for (XWPFParagraph p: paragraphs) {
        List<XWPFRun> runs = p.getRuns();
        for (XWPFRun r: runs) {
           String endText = r.getText(0).replaceFirst("ipsum","hello world");
           r.setText(endText,0);
        }
    }

        document.write(new FileOutputStream(uuid + ".docx"));
        fis.close();
        document.close();

但是,如果我尝试更改文本样式(如粗体),甚至更改字体颜色,则所有“运行”都会改变,不仅是我搜索过的世界。我该怎么做才能更改示例文本中仅单词“ ipsum”的字体样式?

解决方法

您已经得出结论,文本运行是可能具有文本格式的最低文本实体。因此,需要采用一个或多个单词,这些单词应采用不同的格式编入自己的文本行。然后可以格式化这些文本行。

我已经在Split a XWPFRun into multiple runs中回答了这个问题。但针对您的特殊情况,我会再次展示。

具有souce.docx像这样:

enter image description here

代码:

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

import java.util.*;
import java.awt.Desktop;

public class WordFormatWords {

 static void cloneRunProperties(XWPFRun source,XWPFRun dest) { // clones the underlying w:rPr element
  CTR tRSource = source.getCTR();
  CTRPr rPrSource = tRSource.getRPr();
  if (rPrSource != null) {
   CTRPr rPrDest = (CTRPr)rPrSource.copy();
   CTR tRDest = dest.getCTR();
   tRDest.setRPr(rPrDest);
  }
 }

 static void formatWord(XWPFParagraph paragraph,String keyword,Map<String,String> formats) {
  int runNumber = 0;
  while (runNumber < paragraph.getRuns().size()) { //go through all runs,we cannot use for each since we will possibly insert new runs
   XWPFRun run = paragraph.getRuns().get(runNumber);
   XWPFRun run2 = run;
   String runText = run.getText(0);
   if (runText != null && runText.contains(keyword)) { //if we have a run with keyword in it,then

    char[] runChars = runText.toCharArray(); //split run text into characters
    StringBuffer sb = new StringBuffer();
    for (int charNumber = 0; charNumber < runChars.length; charNumber++) { //go through all characters in that run
     sb.append(runChars[charNumber]); //buffer all characters
     runText = sb.toString();
     if (runText.endsWith(keyword)) { //if the bufferend character stream ends with the keyword  
      //set all chars,which are current buffered,except the keyword,as the text of the actual run
      run.setText(runText.substring(0,runText.length() - keyword.length()),0); 
      run2 = paragraph.insertNewRun(++runNumber); //insert new run for the formatted keyword
      cloneRunProperties(run,run2); // clone the run properties from original run
      run2.setText(keyword,0); // set the keyword in run
      for (String toSet : formats.keySet()) { // do the additional formatting
       if ("color".equals(toSet)) {
        run2.setColor(formats.get(toSet));
       } else if ("bold".equals(toSet)) {
        run2.setBold(Boolean.valueOf(formats.get(toSet)));
       }
      }
      run2 = paragraph.insertNewRun(++runNumber); //insert a new run for the next characters
      cloneRunProperties(run,run2); // clone the run properties from original run
      run = run2;
      sb = new StringBuffer(); //empty the buffer
     } 
    }
    run.setText(sb.toString(),0); //set all characters,which are currently buffered,as the text of the actual run

   }
   runNumber++;
  }
 }


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

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

  String[] keywords = new String[]{"ipsum"};
  Map<String,String> formats = new HashMap<String,String>();
  formats.put("bold","true");
  formats.put("color","DC143C");

  for (XWPFParagraph paragraph : doc.getParagraphs()) { //go through all paragraphs
   for (String keyword : keywords) {
    formatWord(paragraph,keyword,formats);
   }
  }

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

  System.out.println("Done");
  Desktop.getDesktop().open(new File("result.docx"));

 }
}

此代码导致这样的result.docx

enter image description here