5

Current output: img

Needed output: img2

above are the snapshots of the .docx and below is the code sample code, I want to change the color of a after it is replaced by @. r.setColor("DC143C") doesn't work:

for (XWPFParagraph p : docx.getParagraphs()) {
        List<XWPFRun> runs = p.getRuns();
        if (runs != null) {
            for (XWPFRun r : runs) {
                String origText = r.getText(0);
                if (origText != null && origText.contains("a")) {
                    origText = origText.replace("a", "@");
                    r.setText(origText, 0);
                }
            }
        }
    }
Andrei Suvorkov
  • 5,559
  • 5
  • 22
  • 48
Ramsha Khan
  • 99
  • 1
  • 8
  • `r.setColor("DC143C");` placed after `r.setText(origText, 0);` works for me. – Axel Richter Oct 29 '16 at 11:44
  • this doesn't work for me. @AxelRichter – Ramsha Khan Oct 29 '16 at 12:00
  • Then we need more information. At least a picture of the Word document. Better a sample document uploaded somewhere. – Axel Richter Oct 29 '16 at 12:03
  • 1
    Oh, `r.setColor("DC143C")` will change the color of the whole run which contains the replaced "a". Is this the problem? But this is far away from "it does not work". – Axel Richter Oct 29 '16 at 12:08
  • UPLOADED sorry i couldnt upload the snapshot of the original document, because i dont have enough points. And setColor("DC143C") really doesnt work for me. It does not change the text color at all. @AxelRichter – Ramsha Khan Oct 29 '16 at 12:21
  • i tried a few more approaches but all of them changes the color of the entire paragraph, not a single character. How can i change the color of just one character? @AxelRichter – Ramsha Khan Oct 29 '16 at 12:23
  • What if the run contains: text, br, text, in this order? – Nathan B Oct 15 '20 at 01:13

1 Answers1

9

If the need is to change the color of just one character then this character must be in its own run. This is because only runs can be styled.

If you have a document containing text already then you must run through all already existing runs and possible split those runs into multiple ones. As the result each string part which shall be styled separately must be in its own run, also if it is only one character.

Example:

import java.io.*;
import org.apache.poi.xwpf.usermodel.*;

import java.awt.Desktop;

import org.apache.poi.openxml4j.exceptions.InvalidFormatException;

public class WordReadAndWrite {

 public static void main(String[] args) throws IOException, InvalidFormatException {

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

  for (XWPFParagraph p : doc.getParagraphs()) { //go through all paragraphs
   int runNumber = 0;
   while (runNumber < p.getRuns().size()) { //go through all runs, we cannot use for each since we will possibly insert new runs
    XWPFRun r = p.getRuns().get(runNumber);
    String runText = r.getText(0);
    if (runText != null && runText.contains("a")) { //if we have a run with an "a" in it, then
     char[] runChars = runText.toCharArray();
     StringBuffer sb = new StringBuffer();
     for (int charNumber = 0; charNumber < runChars.length; charNumber++) { //go through all characters in that run     
      if (runChars[charNumber] == 'a') { //if the charcter is an 'a' then      
       r.setText(sb.toString(), 0); //set all characters, which are current buffered, as the text of the actual run
       r = p.insertNewRun(++runNumber); //insert new run for the '@' as the replacement for the 'a'
       r.setText("@", 0);
       r.setColor("DC143C");
       r = p.insertNewRun(++runNumber); //insert new run for the next characters
       sb = new StringBuffer(); //empty buffer
      } else {
       sb.append(runChars[charNumber]); //buffer all characters which are not 'a's
      }
     }
     r.setText(sb.toString(), 0); //set all characters, which are current buffered, as the text of the actual run
    }
    runNumber++;
   }
  }


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

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

 }
}
Axel Richter
  • 56,077
  • 6
  • 60
  • 87
  • omg! thanks a lot! I have been searching for answers since yesterday, I had a vague picture of splitting the runs but then I didn't know how to. The documentation is not sufficient or maybe I wasn't looking at the right place for answers. Your example is the answer I was looking for. Thanks a lot! – Ramsha Khan Oct 30 '16 at 11:43
  • In all answers you set the text in position 0, why? What if the Run is more complicated than that? – Nathan B Oct 15 '20 at 01:15