Range.replace question

Hi Guys,

I ran into a problem with Range.replace function. My code and
file are listed below. I need to search the word has prefix
then replace the whole word with “Keyword” and red highlight. But the
output was total out of what I expected. Is there anything I did wrong?

Thank you


C# source code:

private void button2_Click(object sender, EventArgs e)
{
    Document doc = new Document("C:\1tempHDM.doc");
    doc.Range.Replace(new Regex(@"<HDM>\w+"), new
    ReplaceEvaluator(MyReplaceEvaluatorCur), false);
    doc.Save("C:\asdf.doc");
    System.Diagnostics.Process.Start("C:\asdf.doc");
}

private ReplaceAction MyReplaceEvaluatorCur(object sender, ReplaceEvaluatorArgs e)
{
    String tmp;
    String keyword;
    DocumentBuilder builder = new DocumentBuilder(e.MatchNode.Document);
    keyword = e.Match.Value;
    keyword = keyword.Substring(keyword.IndexOf(">") + 1);
    builder.MoveTo(e.MatchNode);
    builder.Font.HighlightColor = System.Drawing.Color.Red;
    tmp = "Keyword";//HDMbuilder.keywordReplace(keyword.ToUpper(),
    HDMGeneratorEnum.FormatType.Default);
    builder.Write(tmp);
    e.Replacement = "";
    return ReplaceAction.Replace;
}

Teamplate file C:\1tempHDM.doc :

We hedged on a Index

Spread .

The Strike is Strike

If the is a collar then the upper bound strike is CapStrike , and lower bound is floorStrike

The trade is reset on resetdate of resetperiod on a DayCountConvention basis. And the day difference is DayDiff


What I got

KeywordWe hedged on a

Keyword .

The Strike is Strike

KeywordKeywordIf the is a collar then the upper bound strpStrike , and lower bound is

KeywordKeywordKeywordKeywordTset on resetperiovention basis. And the day difference is

Hi,

I now see the problem. The point is nodes encontered are text runs with several occurrences… Give me several hours, I think I will find out a solution.

Thx for the quick reply. The problem happens even if I have only one
line in the template. ( see below) The result would switch “a” with
“Keyword”

Thank you and I am looking forward to your reply.

Template:

We hedged on a index

Please give a try to the following code:

public void TestReplace()
{
    Document doc = TestUtil.Open("Source.doc");
    doc.Range.Replace(new Regex(@"\]\*\>\w+"), new ReplaceEvaluator(ReplaceEvaluator), false);
    TestUtil.Save(doc, "Result.doc");
}

private ReplaceAction ReplaceEvaluator(object sender, ReplaceEvaluatorArgs args)
{
    DocumentBuilder builder = new DocumentBuilder(args.MatchNode.Document);
    builder.MoveTo(args.MatchNode);
    SplitRun(builder, args.MatchOffset, args.Match.Value.Length, "Keyword");
    return ReplaceAction.Skip;
}

private void SplitRun(DocumentBuilder builder, int offset, int length, string replacement)
{
    Run run = (Run)builder.CurrentNode;
    Run prevRun = new Run(run.Document, run.Text.Substring(0, offset));
    offset += length;
    Run nextRun = new Run(run.Document, run.Text.Substring(offset, run.Text.Length - offset));
    builder.InsertNode(prevRun);
    builder.Font.HighlightColor = Color.Red;
    builder.Write(replacement);
    builder.InsertNode(nextRun);
    run.Remove();
}

The idea is that if we encounter a run with one of more XXX occurrences, we replace it with three runs:

  1. The first run is based on the text before the occurrence.
  2. The second run is the replacement inserted by using the builder with appropriate formatting set.
  3. The third run is based on the text after thу occurrence.

The original run is then removed.

I hope this will help you to adjust this algorithm to your needs. Tell me if something is wrong there.

Hi, :frowning: it’s still not working for the following template. It replaced notional first, then at notionEnglish, the whole notionalEnglish was trimmed off, and I got an exception.

----------------------------------------

We hedged on a NotionalEnglish

Notional

----------------------------------------

Please attach the template in question and tell me what exception you got. Also, please clarify what was wrong with “NotionalEnglish”. I assumed the goal was to replace the whole occurrences fitting the XXX pattern, i.e. NotionalEnglish was to completely replaced. Is it correct?

I am using the code you listed above. The error message I got was “System.ArgumentOutOfRangeException” - StartIndex cannot be larger than length of string. The line got errored out was

Run nextRun = new Run(run.Document, run.Text.Substring(offset, run.Text.Length - offset));

I’ve attached the template.

Thank you

Alan

It seems like the task is getting more complex My bad, I forgot that the match may be spread over several runs too. Here’s a refined solution:

[Test]
public void TestReplace()
{
    Document doc = TestUtil.Open("Source.doc");
    doc.Range.Replace(new Regex(@"\]\*\>\w+"), new ReplaceEvaluator(ReplaceEvaluator), false);
    TestUtil.SaveShow(doc, "Result.doc");
}

private ReplaceAction ReplaceEvaluator(object sender, ReplaceEvaluatorArgs args)
{
    DocumentBuilder builder = new DocumentBuilder(args.MatchNode.Document);
    builder.MoveTo(args.MatchNode);
    SplitRun(builder, args.MatchOffset, args.Match.Value.Length, "Keyword");
    return ReplaceAction.Skip;
}

private void SplitRun(DocumentBuilder builder, int offset, int length, string replacement)
{
    Run firstRun = (Run)builder.CurrentNode;
    Run prevRun = new Run(firstRun.Document, firstRun.Text.Substring(0, offset));
    int total;
    ArrayList runs = GetRunsToRemove(firstRun, length, out total);
    Run lastRun = (Run)runs[runs.Count - 1];
    int lastRunLength = lastRun.Text.Length;
    int lastRunOffset = (offset + length) - (total - lastRunLength);
    Run nextRun = new Run(lastRun.Document, lastRun.Text.Substring(lastRunOffset, lastRunLength - lastRunOffset));
    builder.InsertNode(prevRun);
    builder.Font.HighlightColor = Color.Red;
    builder.Write(replacement);
    builder.MoveTo(lastRun);
    builder.InsertNode(nextRun);
    foreach (Run run in runs)
        run.Remove();
}

private ArrayList GetRunsToRemove(Run firstRun, int matchLength, out int total)
{
    total = 0;
    Run run = firstRun;
    ArrayList runs = new ArrayList();
    while (total < matchLength)
    {
        total += run.Text.Length;
        runs.Add(run);
        run = (Run)run.NextSibling;
    }
    return runs;
}

I hope it will work now. If something is wrong, feel free to post it here.