Thanks for sharing the detail. Please note that all text of the document is stored in runs of text. In your document, each line of text is in a single Run node. The exception you are facing is due to SplitRun method. This method split the single Run node.
In ReplaceAction, the SplitRun method is called which split the single Run node multiple. E.g the input document has Run node with text ‘This is the age of the train.’. After the execution of ReplaceAction, there are four Run nodes in the Aspose.Words DOM. Please see the attached DOM image for detail. The run does not exist in mNodeLookup. This is the reason of exception.
// Look up the real start and end node to be highlighted from the clone document node.
Run startRun = (Run)mNodeLookup[(Node)runs]; //I GET THE ERROR HERE
Run endRun = (Run)mNodeLookup[(Node)runs[runs.Count - 1]];
Secondly, your document does not contains the revisions. I have added the insert and delete revisions in the attached document. I have used the following code snippet to find the text ‘the’ and bold it by using following code snippet and have not found any with ‘Find and Replace’.
Could you please attach your input and expected output Word document here for testing? I will investigate the issue on my side and provide you more information.
Please also share what exact you want to achieve by using Aspose.Words. We will then provide you more information about your query along with code.
Document doc = new Document(MyDir + "Revision.docx");
Regex regex = new Regex("the", RegexOptions.IgnoreCase);
doc.Range.Replace(regex, new ReplaceEvaluatorFindAndHighlight(), true);
doc.Save(MyDir + "Out.docx");
private class ReplaceEvaluatorFindAndHighlight : IReplacingCallback
/// This method is called by the Aspose.Words find and replace engine for each match.
/// This method highlights the match string, even if it spans multiple runs.
ReplaceAction IReplacingCallback.Replacing(ReplacingArgs e)
// This is a Run node that contains either the beginning or the complete match.
Node currentNode = e.MatchNode;
// The first (and may be the only) run can contain text before the match,
// in this case it is necessary to split the run.
if (e.MatchOffset > 0)
currentNode = SplitRun((Run)currentNode, e.MatchOffset);
// This array is used to store all nodes of the match for further highlighting.
ArrayList runs = new ArrayList();
// Find all runs that contain parts of the match string.
int remainingLength = e.Match.Value.Length;
(remainingLength > 0) &&
(currentNode != null) &&
(currentNode.GetText().Length <= remainingLength))
remainingLength = remainingLength - currentNode.GetText().Length;
// Select the next Run node.
// Have to loop because there could be other nodes such as BookmarkStart etc.
currentNode = currentNode.NextSibling;
while ((currentNode != null) && (currentNode.NodeType != NodeType.Run));
// Split the last run that contains the match if there is any text left.
if ((currentNode != null) && (remainingLength > 0))
// Now highlight all runs in the sequence.
foreach (Run run in runs)
run.Font.Bold = true;
// Signal to the replace engine to do nothing because we have already done all what we wanted.