ReplaceEvaluator problem

Hello,

I’m trying to replace a sequence with a mergefield but cannot do so. The attached document contains 2 times the sequence but the ReplaceEvaluator event is called more than that.

Here is the code I use :

<span style=“font-size: 10pt; font-family: “Courier New”;” lang=“EN-US”> public static
void
InsertOptionMergeFields()

{

ResourcesLoader.Load();

Document doc = new Document(@“ReplaceMFpb.doc”);

doc.Range.Replace(new Regex(“4µ@3#\d+@W_#S”), new ReplaceEvaluator(InsertOptionMergeFieldEvent), false);

}

private static ReplaceAction InsertOptionMergeFieldEvent(object sender, ReplaceEvaluatorArgs e)

{

DocumentBuilder builder = new DocumentBuilder(e.MatchNode.Document as Document);

Run matchRun = (Run)e.MatchNode;

string runText = matchRun.Text;

Run run = (Run)e.MatchNode.Clone(true);

run.Text = runText.Substring(runText.IndexOf(e.Match.Value) + e.Match.Value.Length);

matchRun.Text = runText.Substring(0, runText.IndexOf(e.Match.Value));

e.MatchNode.ParentNode.InsertAfter(run, e.MatchNode);

builder.MoveTo(run);

builder.InsertField(“MERGEFIELD toto”, “”);

return ReplaceAction.Skip;

}

Any help would be greatly appreciated.

Regards,

Hi

Thanks for your request. Actually, I see that the sequence occurs 3 times in the document. I modified your code a bit and now it works fine. I used the technique described here:

http://www.aspose.com/documentation/file-format-components/aspose.words-for-.net-and-java/find-and-highlight-text.html

Document doc = new Document(@“Test001\in.doc”);

doc.Range.Replace(new Regex(“4µ@3#\d+@W_#S”), new ReplaceEvaluator(InsertOptionMergeFieldEvent), false);

doc.Save(@“Test001\out.doc”);

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

private static ReplaceAction InsertOptionMergeFieldEvent(object sender, ReplaceEvaluatorArgs 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 removing.

ArrayList runs = new ArrayList();

// Find all runs that contain parts of the match string.

int remainingLength = e.Match.Value.Length;

while (

(remainingLength > 0) &&

(currentNode != null) &&

(currentNode.GetText().Length <= remainingLength))

{

runs.Add(currentNode);

remainingLength = remainingLength - currentNode.GetText().Length;

// Select the next Run node.

// Have to loop because there could be other nodes such as BookmarkStart etc.

do

{

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))

{

SplitRun((Run)currentNode, remainingLength);

runs.Add(currentNode);

}

// Create Document Buidler aond insert MergeField

DocumentBuilder builder = new DocumentBuilder(e.MatchNode.Document as Document);

builder.MoveTo((Run) runs[runs.Count - 1]);

builder.InsertField(“MERGEFIELD toto”, “”);

// Now remove all runs in the sequence.

foreach (Run run in runs)

run.Remove();

// Signal to the replace engine to do nothing because we have already done all what we wanted.

return ReplaceAction.Skip;

}

///

/// Splits text of the specified run into two runs.

/// Inserts the new run just after the specified run.

///

private static Run SplitRun(Run run, int position)

{

Run afterRun = (Run)run.Clone(true);

afterRun.Text = run.Text.Substring(position);

run.Text = run.Text.Substring(0, position);

run.ParentNode.InsertAfter(afterRun, run);

return afterRun;

}

Hope this helps.

Best regards.

Hello,

Thank you very much for the code. It works great.

Kind regards,

**Hi Alexey,

my question is: How can you automatically have a pointer to the last node of a Match.
Let say my match is all the text contained between START and END, which are arbitrary data.
Consider I want to repeat the structure of my Match sequence a couple of times, base on a certain number of records I’m working with.

We know e.MatchNode gives us a pointer to the first node. But what If I want to know all the nodes or runs from the starting one to the last one ?

current.NextSibling() won’t work for example if my data is contained inside a table with cells.

In that case, I think we may need to go up several times until we find the a root node, then traverse it down recursively until we reach our last node.

Do you have a better idea for me ?
Also, I don’t always know if my Match will be in table, since I want to repeat any data contained in any Nodes structure.

Thanks.**

Hi Patrick,

Thanks for your inquiry. I think, you can use the same technique as suggested in the following article:

http://www.aspose.com/documentation/.net-components/aspose.words-for-.net/howto-find-and-highlight-text.html

The code provided in this article collects all nodes in the match and highlights them.

Hope this helps. Please let me know if you need more information, we are always glad to help you.

Best regards,