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?
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;
}
}
Hi
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.
Hi
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.
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.