java - 使用 Java Apache POI 从 docx 文件中更改特定单词的字体样式
问题描述
我正在使用 Apache POI XWPF 来操作 docx 文件,我需要更新一些段落的单词并更改它的字体样式。更新一个单词没关系,假设我的docx内容有以下段落:
Lorem ipsum dolor sit amet, consectetur adipiscing elit。整数 pretium sodales nisl, ut ornare ligula vehicula vitae。Fusce non magna feugiat,sagittis massa at,发酵罐。Curabitur auctor leo vitae sem tempus, facilisis feugiat orci vestibulum。Mauris molestie sem sem, id venenatis arcu congue id。Duis nulla quam,commodo vel dolor eget,tempor varius sem。Pellentesque gravida、lectus eu mollis pretium、sapien nibh consectetur lacus、非 pellentesque lectus ipsum ornare eros。Maecenas 在 magna nunc。
Nulla sagittis aliquam maximus。Cras faucibus id neque sed faucibus。Faucibus orci luctus et ultrices posuere cubilia curae 中的前庭前庭;Phasellus infantum nulla sed nibh varius maximus。Pellentesque dui lorem, luctus non lorem a, blandit lacinia arcu。Nunc porttitor erat ut elit hendrerit malesuada。Sed ut ex ultricies,rutrum est ut,vulputate orci。Suspendisse vitae diam ullamcorper,pulvinar tellus vitae,feugiat ex。在 hac habitasse platea dictumst 中。类 aptent taciti socialsqu ad litora torquent per conubia nostra, per inceptos himenaeos。Proin massa lectus, venenatis eget massa a, fringilla 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
这样的:
代码:
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
这样的:
推荐阅读
- python - 如何解决请求无法通过 VPN 工作?
- reactjs - 为什么我在使用 webpack 运行“npm run build”时得到散列的 .jpeg 文件
- oracle - toad for oracle 中的外部表数据错误
- nginx - nginx反向代理背后的grafana
- python - 在 Python 中使用 openpyxl 进行 Excel 条件格式设置 - 边框
- sockets - 在内核模块中使用蓝牙套接字
- javascript - 花式树 - 可排序获取节点的顺序,仅在相同的嵌套级别排序
- php - 如何用单引号替换 &apos ($song[1])
- asp.net-core-mvc - asp.net mvc 将自定义列添加到身份角色表
- java - 带有蓝牙设备名称的Android自定义文本视图