英文:
Change font style in a specific word from docx file using Java Apache POI
问题
我正在使用Apache POI XWPF来操作一个docx文件,我需要更新段落中的一些单词并更改其字体样式。要更新单个单词是可以的,假设我的docx内容如下所示:
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer pretium sodales nisl, ut ornare ligula vehicula vitae. Fusce non magna
feugiat, sagittis massa at, fermentum nibh. 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, non pellentesque lectus ipsum
ornare eros. Maecenas at magna nunc.Nulla sagittis aliquam maximus. Cras faucibus id neque sed faucibus. Vestibulum ante ipsum primis in faucibus orci luctus et
ultrices posuere cubilia curae; Phasellus fermentum 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. In hac habitasse
platea dictumst. Class aptent taciti sociosqu 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();
但是,如果我尝试更改文本样式,比如加粗,甚至改变字体颜色,所有的“run”都会改变,不仅仅是我搜索到的单词。我要如何才能仅更改示例文本中的单词“ipsum”的字体样式呢?
英文:
I'm using Apache POI XWPF to manipulate a docx file, I need to update some words of paragraph and change the font style of it. For updating a single word, it's ok, let's assume that my docx content has the paragraphs bellow:
>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer pretium sodales nisl, ut ornare ligula vehicula vitae. Fusce non magna
> feugiat, sagittis massa at, fermentum nibh. 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, non pellentesque lectus ipsum
> ornare eros. Maecenas at magna nunc.
>
>Nulla sagittis aliquam maximus. Cras faucibus id neque sed faucibus. Vestibulum ante ipsum primis in faucibus orci luctus et
> ultrices posuere cubilia curae; Phasellus fermentum 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. In hac habitasse
> platea dictumst. Class aptent taciti sociosqu ad litora torquent per
> conubia nostra, per inceptos himenaeos. Proin massa lectus, venenatis
> eget massa a, fringilla molestie nisl.
I just do something like it, in this case, the code works, I just want to update the word "ipsum" to "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();
But if I try to change the text style, like bold, or even change the font color, all of "run" will change, not only the world that I've searched. What I have to do to change the font style only of the word "ipsum" in the example text?
答案1
得分: 3
你已经得出结论,文本运行是可能具有文本格式的最低文本实体。因此,需要将需要以不同格式进行格式化的单词或单词单独放入其自己的文本运行中。然后可以对这些文本运行进行格式化。
我已经在 https://stackoverflow.com/questions/57132951/split-a-xwpfrun-into-multiple-runs/57186765 中回答过这个问题。但是我会针对你的特殊情况再次进行展示。
假设 source.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) {
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()) {
XWPFRun run = paragraph.getRuns().get(runNumber);
XWPFRun run2 = run;
String runText = run.getText(0);
if (runText != null && runText.contains(keyword)) {
char[] runChars = runText.toCharArray();
StringBuffer sb = new StringBuffer();
for (int charNumber = 0; charNumber < runChars.length; charNumber++) {
sb.append(runChars[charNumber]);
runText = sb.toString();
if (runText.endsWith(keyword)) {
run.setText(runText.substring(0, runText.length() - keyword.length()), 0);
run2 = paragraph.insertNewRun(++runNumber);
cloneRunProperties(run, run2);
run2.setText(keyword, 0);
for (String toSet : formats.keySet()) {
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);
cloneRunProperties(run, run2);
run = run2;
sb = new StringBuffer();
}
}
run.setText(sb.toString(), 0);
}
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()) {
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
的文档,如下所示:
(图片已省略)
英文:
You have concluded already that the text run is the lowest text entity which may have text formatting. So the need is taking a word or words which shall be formatted differently into their own text runs. Then one can format those text runs.
I have answered this already in https://stackoverflow.com/questions/57132951/split-a-xwpfrun-into-multiple-runs/57186765. But I will show it again for your special case.
Having the souce.docx
like this:
Code:
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"));
}
}
This code leads to a result.docx
like this:
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论