We're sorry Aspose doesn't work properply without JavaScript enabled.

Free Support Forum - aspose.com

Mark only the word changed in the replace

Hi to you all

I am evaluating the Aspose.Words for Java and I'm really liking. Clean interface and a very good documentation :-)

I have a problem in the Range#replace() function. Running through the document and changing certain words is what I already am able to do. But now, I want to mark only those words with the color red. The ReplaceEvaluatorArgs#getMatchNode() function, gives me access to the match run, but the Run may contain more text than I am replacing, making all text red.


What solution you may think is best to this problem?


Thanks for the support

Hi<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

Thanks for your request. Please try using the following code:

//Create regex

Pattern regex = Pattern.compile("test");

//Open document

Document doc = new Document("C:\\Temp\\in.doc");

//find placeholders

doc.getRange().replace(regex, new MyReplaceEvaluator(), true);

//Save document

doc.save("C:\\Temp\\out.doc");

===================================================================

public class MyReplaceEvaluator implements ReplaceEvaluator

{

public synchronized int replace(Object object, ReplaceEvaluatorArgs e) throws Exception

{

//Get MatchNode

Run run1 = (Run)e.getMatchNode();

//Create two Runs

Run run2 = (Run)run1.deepClone(true);

Run run3 = (Run)run1.deepClone(true);

//Get index of match value

int index = run1.getText().indexOf(e.getMatch().group());

//split run that contains matched text

run3.setText(run1.getText().substring(index + e.getMatch().group().length()));

run2.setText(run1.getText().substring(index, index + e.getMatch().group().length()));

run1.setText(run1.getText().substring(0, index));

//Insert runs into the document

run1.getParentParagraph().insertAfter(run2, run1);

run2.getParentParagraph().insertAfter(run3, run2);

//Change formating of the matched word

run2.getFont().setHighlightColor(Color.YELLOW);

return ReplaceAction.SKIP;

}

}

Hope this helps.

Best regards.

Really thanks for the reply.



Is almost exactly that.



My only problem now is when the string that goes to the run2 is not the same length as the word we are replacing.


Many thanks for the help


Hi<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

If you need, I can try to help you to resolve this problem. If so, please attach your document and provide me Regex you are using to search words in the document.

Best regards.


The attached text document is my Java test class and the other is my Word test file.

Many thanks for the help

Hi<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

Thank you for additional information. The problem occurs because matched value consists of several Run nodes. Partially you can solve this issue by using:

doc.joinRunsWithSameFormatting();

However, if Runs in your document have different formatting, then you should combine runs programmatically.

Best regards.

I changed the word “actual” in the previous post to see if there was a magical solution :-), but this is not the main issue.

In the attached document on this post, you have a good behaved document, and the length issue is still there.
If you try the script with this file, will give a StringIndexOutOfBoundsException.

Inserting nodes, only works when the string added and the string matched are the same length.

Could you try some workaround to this, please?


Once again, many thanks for the help


Hi<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

Thanks for your request. Please try using the following code:

Document doc = new Document("C:\\Temp\\f.docx");

MyReplaceEvaluator rep = new MyReplaceEvaluator();

Range reprange = doc.getRange();

reprange.replace(Pattern.compile("([\\wзЗаАбБйЙнНуУъЪгГвф-]+)"), rep, false);

doc.save("c:\\Temp\\ff.docx");

====================================================================

public class MyReplaceEvaluator implements ReplaceEvaluator

{

public synchronized int replace(Object object, ReplaceEvaluatorArgs e) throws Exception

{

//Get MatchNode

Run matchedRun = (Run)e.getMatchNode();

//If word will of more than one run

ArrayList mainTextNodes = new ArrayList();

//Get word

String word = e.getMatch().group();

//This run can contain whole mathed word or part of the word

//When run contains only part of the word IndexOf will return negative value

//Here we search for word start index

int index = matchedRun.getText().lastIndexOf(word);

int wordLength = word.length();

while(index < 0)

{

index = matchedRun.getText().lastIndexOf(word.substring(0, wordLength--));

}

//matched run can contain text before matched word, sa me should split run here

if(index > 0)

{

Run beforeRun = (Run)matchedRun.deepClone(true);

beforeRun.setText(matchedRun.getText().substring(0, index));

matchedRun.getParentNode().insertBefore(beforeRun, matchedRun);

}

//If whole word is place in the mathed node

if(matchedRun.getText().length() > index+word.length())

{

Run mainTextRun = (Run)matchedRun.deepClone(true);

mainTextRun.setText(word);

matchedRun.getParentNode().insertBefore(mainTextRun, matchedRun);

matchedRun.setText(matchedRun.getText().substring(index+word.length()));

mainTextNodes.add(mainTextRun);

}

else

{

//word is spanned to several Run nodes

matchedRun.setText(matchedRun.getText().substring(index));

mainTextNodes.add(matchedRun);

//Get length of the part of teh word that goes to the next run

int currentIdx = word.length() - matchedRun.getText().length();

Run nextRun = (Run)matchedRun.getNextSibling();

while(currentIdx > 0)

{

if(nextRun.getText().length()>currentIdx)

{

break;

}

else

{

mainTextNodes.add(nextRun);

currentIdx = currentIdx - nextRun.getText().length();

nextRun = (Run)nextRun.getNextSibling();

}

}

//Now we should split last run in sequence, if there is text after matched word

if(nextRun!=null)

{

if(nextRun.getText().length()==currentIdx)

{

mainTextNodes.add(nextRun);

}

else

{

Run lastRun = (Run)nextRun.deepClone(true);

lastRun.setText(nextRun.getText().substring(0, currentIdx));

nextRun.getParentNode().insertBefore(lastRun, nextRun);

mainTextNodes.add(lastRun);

}

}

}

//hilight all runs in the sequence

for(int i=0; i<mainTextNodes.size(); i++ )

{

Run currentRun = (Run)mainTextNodes.get(i);

currentRun.getFont().setHighlightColor(Color.YELLOW);

}

return ReplaceAction.SKIP;

}

}

Hope this helps. Please let me know in case of any issues.

Best regards.

This was almost what i needed but I already modify it to suit my needs.

Thank You very much for the support.

I alredy convinced my boss that was worth it. Now he jus have to convince the guy with the money :slight_smile: