Word Chart text highlight problem

Hi Team,
Highlighting text in word chart not happening. using following code:

FindReplaceOptions option1 = new FindReplaceOptions();
option1.ApplyFont.HighlightColor = System.Drawing.Color.Yellow;
option1.FindWholeWordsOnly = true;
option1.ReplacingCallback = new ReplaceEvaluatorFindAndHighlight();
option1.Direction = FindReplaceDirection.Backward;

Document doc = new Document(filePath);
Regex regx = new Regex("Word Two", RegexOptions.IgnoreCase);
doc .Range.Replace(regx, "", option1);

Sample word file - charts-word-test.docx (39.5 KB)

@Jaibir I am afraid currently Aspose.Words does not allow to use find/replace functionality in charts.

We have opened the following new feature request in our internal issue tracking system and will deliver their fixes according to the terms mentioned in Free Support Policies.

Issue ID(s): WORDSNET-26423

You can obtain Paid Support Services if you need support on a priority basis, along with the direct access to our Paid Support management team.

Regarding your code, it is not required to use IReplacingCallback to highlight the matched text. It is better to use substitutions:

FindReplaceOptions option1 = new FindReplaceOptions();
option1.ApplyFont.HighlightColor = System.Drawing.Color.Yellow;
option1.FindWholeWordsOnly = true;
option1.UseSubstitutions = true;
option1.Direction = FindReplaceDirection.Backward;

Document doc = new Document(@"C:\Temp\in.docx");
Regex regx = new Regex("Word Two", RegexOptions.IgnoreCase);
doc.Range.Replace(regx, "$0", option1);
doc.Save(@"C:\Temp\out.docx");
1 Like

Thank you so much for the quick response. Looking forward for the solution.

Warm Regards
Jaibir Singh

1 Like

Hi @alexey.noskov
Can you please also tell. How to skip highlighting in comments ?

Thanks in advance!

@Jaibir You can use IReplacingCallback to skip comments. See the following code:

FindReplaceOptions option1 = new FindReplaceOptions();
option1.ApplyFont.HighlightColor = System.Drawing.Color.Yellow;
option1.FindWholeWordsOnly = true;
option1.UseSubstitutions = true;
option1.Direction = FindReplaceDirection.Backward;
option1.ReplacingCallback = new SkipCommentsCallback();

Document doc = new Document(@"C:\Temp\in.docx");
Regex regx = new Regex("Word Two", RegexOptions.IgnoreCase);
doc.Range.Replace(regx, "$0", option1);
doc.Save(@"C:\Temp\out.docx");
public class SkipCommentsCallback : IReplacingCallback
{
    public ReplaceAction Replacing(ReplacingArgs args)
    {
        if(args.MatchNode.GetAncestor(NodeType.Comment)!=null)
            return ReplaceAction.Skip;

        return ReplaceAction.Replace;
    }
}
1 Like

Thank you @alexey.noskov .
I also few more problems. One of them is, how can we highlight list of keywords and add comments for which comments exits. It is not necessary that all of the keywords will have the comments And the comment should be added with ‘**’ this two asterisk characters with superscript just after the highlighted keywords. For reference attaching screenshot.

@Jaibir You can use the following code to achieve this:

Document doc = new Document(@"C:\Temp\in.docx");

// Get runs with superscript **
List<Run> runToCommet = doc.GetChildNodes(NodeType.Run, true).Cast<Run>()
    .Where(r => r.Font.Superscript && r.Text == "**").ToList();

foreach (Run r in runToCommet)
{
    Comment c = new Comment(doc, "Aspose", "AW", DateTime.Now);
    c.AppendChild(new Paragraph(doc));
    c.FirstParagraph.AppendChild(new Run(doc, "This is comment text"));

    r.ParentNode.InsertBefore(new CommentRangeStart(doc, c.Id), r);
    r.ParentNode.InsertAfter(new CommentRangeEnd(doc, c.Id), r);
    r.ParentNode.InsertAfter(c, r);
}

doc.Save(@"C:\Temp\out.docx");

in.docx (12.5 KB)
out.docx (11.2 KB)

Thank you @alexey.noskov ,
There is slight difference in my requirement. For references take a look into following code:

List<KeywordClass> listToHighlight = new List<KeywordClass>();
listToHighlight.add(new KeywordClass("highlight-1", ""));
listToHighlight.add(new KeywordClass("highlight-Comment-1", "comment 1 for text"));
listToHighlight.add(new KeywordClass("highlight-2", ""));
listToHighlight.add(new KeywordClass("highlight-Comment-2", "comment 2 for text"));
FindReplaceOptions option1 = new FindReplaceOptions();

option1.ApplyFont.HighlightColor = System.Drawing.Color.Yellow;
option1.FindWholeWordsOnly = true;
option1.UseSubstitutions = true;
option1.Direction = FindReplaceDirection.Backward;

Document doc = new Document(@"C:\Temp\in.docx");
Regex regx = new Regex("Word Two", RegexOptions.IgnoreCase);
doc.Range.Replace(regx, "$0", option1);
doc.Save(@"C:\Temp\out.docx");

public class KeywordClass
{
  public KeywordClass(string _keyword, string _comment)
  {
     keyword = _keyword;
     comment = _comment;
  }
  public string keyword{get;set;}
  public string comment{get;set;}
}

As in the above code we have a listToHighlight list with all keywords and comments. Now we need to highlight all the list keywords with comments. Which keywords do not have comments, will get highlighted And which has comments, we will highlight it as well as sufix the keyword with ** and add comment on **.
Following is the Input doc file.
in.docx (13.1 KB)

@Jaibir Thank you for additional information. You can achieve this using the following code:

List<KeywordClass> listToHighlight = new List<KeywordClass>();
listToHighlight.Add(new KeywordClass("highlight-1", ""));
listToHighlight.Add(new KeywordClass("highlight-Comment-1", "comment 1 for text"));
listToHighlight.Add(new KeywordClass("highlight-2", ""));
listToHighlight.Add(new KeywordClass("highlight-Comment-2", "comment 2 for text"));

FindReplaceOptions option1 = new FindReplaceOptions();
option1.ApplyFont.HighlightColor = System.Drawing.Color.Yellow;
option1.FindWholeWordsOnly = true;
option1.UseSubstitutions = true;
option1.Direction = FindReplaceDirection.Backward;

Document doc = new Document(@"C:\Temp\in.docx");
// Create regext to match all keywords in the document within one `Replace` call.
string regexString = String.Join("|", listToHighlight.Select(x => Regex.Escape(x.keyword)));
Regex regx = new Regex(regexString, RegexOptions.IgnoreCase);
doc.Range.Replace(regx, "$0", option1);

// add comment after the keywords,where required.
List<KeywordClass> keywordsWithComments = listToHighlight.Where(c => !string.IsNullOrEmpty(c.comment)).ToList();
List<Run> runs = doc.GetChildNodes(NodeType.Run, true).Cast<Run>().ToList();
foreach (KeywordClass keyword in keywordsWithComments)
{
    List<Run> runsTobeCommented = runs.Where(r => r.Text == keyword.keyword).ToList();
    foreach (Run r in runsTobeCommented)
    {
        Run asterix = r.ParentNode.InsertAfter(new Run(doc, "**"), r);
        asterix.Font.Superscript = true;

        Comment c = new Comment(doc, "Aspose", "AW", DateTime.Now);
        c.AppendChild(new Paragraph(doc));
        c.FirstParagraph.AppendChild(new Run(doc, keyword.comment));

        asterix.ParentNode.InsertBefore(new CommentRangeStart(doc, c.Id), r);
        asterix.ParentNode.InsertAfter(new CommentRangeEnd(doc, c.Id), r);
        asterix.ParentNode.InsertAfter(c, r);
    }
}

doc.Save(@"C:\Temp\out.docx");

out.docx (11.9 KB)

1 Like

Hi @alexey.noskov ,
Thank you for the above code.
Now next requirement in this is. we need to store the found keywords into a list along with page number and occurrences by page number. Document can be more than 100 pages, so wee need to write optimize code.

Thanks!

@Jaibir You can use LayoutCollector to determine page number where node is located. So in your case after adding comments, you can create LayoutCollector, loop through the Run nodes with the matched keyword and determine page where the Run is located. LayoutCollector should be create after adding the comments, because upon creating LayoutCollector Aspose.Words builds the document layout, changing the document might affect the document layout.
Simplified code might looks like this:

List<KeywordClass> listToHighlight = new List<KeywordClass>();
listToHighlight.Add(new KeywordClass("highlight-1", ""));
listToHighlight.Add(new KeywordClass("highlight-Comment-1", "comment 1 for text"));
listToHighlight.Add(new KeywordClass("highlight-2", ""));
listToHighlight.Add(new KeywordClass("highlight-Comment-2", "comment 2 for text"));

FindReplaceOptions option1 = new FindReplaceOptions();
option1.ApplyFont.HighlightColor = System.Drawing.Color.Yellow;
option1.FindWholeWordsOnly = true;
option1.UseSubstitutions = true;
option1.Direction = FindReplaceDirection.Backward;

Document doc = new Document(@"C:\Temp\in.docx");
// Create regext to match all keywords in the document within one `Replace` call.
string regexString = String.Join("|", listToHighlight.Select(x => Regex.Escape(x.keyword)));
Regex regx = new Regex(regexString, RegexOptions.IgnoreCase);
doc.Range.Replace(regx, "$0", option1);

// add comment after the keywords,where required.
List<KeywordClass> keywordsWithComments = listToHighlight.Where(c => !string.IsNullOrEmpty(c.comment)).ToList();
List<Run> runs = doc.GetChildNodes(NodeType.Run, true).Cast<Run>().ToList();
foreach (KeywordClass keyword in keywordsWithComments)
{
    List<Run> runsTobeCommented = runs.Where(r => r.Text == keyword.keyword).ToList();
    foreach (Run r in runsTobeCommented)
    {
        Run asterix = r.ParentNode.InsertAfter(new Run(doc, "**"), r);
        asterix.Font.Superscript = true;

        Comment c = new Comment(doc, "Aspose", "AW", DateTime.Now);
        c.AppendChild(new Paragraph(doc));
        c.FirstParagraph.AppendChild(new Run(doc, keyword.comment));

        asterix.ParentNode.InsertBefore(new CommentRangeStart(doc, c.Id), r);
        asterix.ParentNode.InsertAfter(new CommentRangeEnd(doc, c.Id), r);
        asterix.ParentNode.InsertAfter(c, r);
    }
}

// Create LayoutCollector to detect page indexes where keywords appear.
LayoutCollector collector = new LayoutCollector(doc);
foreach (KeywordClass keyword in listToHighlight)
{
    List<Run> keywordsRuns = runs.Where(r => r.Text == keyword.keyword).ToList();
    Console.Write($"'{keyword.keyword}' appears on ");
    foreach (Run r in keywordsRuns)
        Console.Write(collector.GetStartPageIndex(r) + ",");

    Console.WriteLine(" pages.");
}

doc.Save(@"C:\Temp\out.docx");
1 Like

Hi @alexey.noskov
Thank you for the code. Need 1 more updation in it. Please check the image. It is adding comment on test instead of **.

@Jaibir You should simply check the code that adds comment like this:

asterix.ParentNode.InsertBefore(new CommentRangeStart(doc, c.Id), asterix);
asterix.ParentNode.InsertAfter(new CommentRangeEnd(doc, c.Id), asterix);
asterix.ParentNode.InsertAfter(c, asterix);
1 Like