Range.Replace how to replace first occurence only?

Hello,
I’m replacing text tags inside a document with the following structure: @XXX.
I need to find a way to replace the first occurence only of the tag inside the document.
With conventional regex.Replace method (Regex.Replace Method (String, String, Int32)) this can be achieved by doing something like this:

var regex = new Regex(new Regex(@"@XXX?"));
var test = regex.Replace("Hello World @XXX have a great day! @XXX", "Test", 1);

so test would be: “Hello World Test have a great day! @XXX

I cannot find a way to achieve this with Aspose Words Range.Replace Method(Regex, string).
Maybe I can override the method? Or modify the IReplacingCallback interface?

Any solution would be very much appreciated.
Thanks for your help,
Silvia

Hi Silvia,

Thanks for your inquiry. Please use the following code example to achieve your requirements. Hope this helps you. Please let us know if you have any more queries.

Document doc = new Document(MyDir + "in.docx");
doc.Range.Replace(new Regex("XXX"), new ReplaceFirstOccourance("Hello World"), true);
doc.Save(MyDir + "Out.docx");
class ReplaceFirstOccourance : IReplacingCallback
{
    String replaceText = "";
    private int mMatchNumber = 0;
    public ReplaceFirstOccourance(String text)
    {
        replaceText = text;
    }
    /// 
    /// This method is called by the Aspose.Words find and replace engine for each match.
    /// 
    ReplaceAction IReplacingCallback.Replacing(ReplacingArgs e)
    {
        // This is a Run node that contains either the beginning or the complete match.
        Node currentNode = e.MatchNode;
        mMatchNumber++;
        if (mMatchNumber == 1)
        {
            // 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.Write(replaceText);
            // 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;
    }
    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;
    }
}