如何使用 OpenXML 突出显示句子中的文本?

How to highlight text in a sentence using OpenXML?

我正在使用以下代码在 MS Word 文档中搜索和突出显示文本,它适用于第 1 点但不适用于第 2 点:

1. John Alter 

我搜索 AlterJohn,它突出显示 John/Alter - 有效。

2. I am going to school

我搜索 going,它突出显示了 going 但它更改了它的顺序 I am to school going - 不起作用。

如何修正第2点?下面是我的代码。

private void HighLightText(Paragraph paragraph, string text)
{
    string textOfRun = string.Empty;
    var runCollection = paragraph.Descendants<DocumentFormat.OpenXml.Wordprocessing.Run>();
    DocumentFormat.OpenXml.Wordprocessing.Run runAfter = null;

    //find the run part which contains the characters
    foreach (DocumentFormat.OpenXml.Wordprocessing.Run run in runCollection)
    {
        if (!string.IsNullOrWhiteSpace(paragraph.InnerText) &&  paragraph.InnerText != "\s")
            textOfRun = run.GetFirstChild<DocumentFormat.OpenXml.Wordprocessing.Text>().Text;                                  

         if (textOfRun.IndexOf(text, StringComparison.OrdinalIgnoreCase) >= 0)
         {    
             //remove the character from this run part
             run.GetFirstChild<DocumentFormat.OpenXml.Wordprocessing.Text>().Text = Regex.Replace(textOfRun, text, string.Empty, RegexOptions.IgnoreCase);//textOfRun.Replace(text, string.Empty);
             runAfter = run;
             break;    
         }    
     }

     //create a new run with your customization font and the character as its text
     DocumentFormat.OpenXml.Wordprocessing.Run HighLightRun = new DocumentFormat.OpenXml.Wordprocessing.Run();
     DocumentFormat.OpenXml.Wordprocessing.RunProperties runPro = new DocumentFormat.OpenXml.Wordprocessing.RunProperties();
     Highlight highlight = new Highlight() { Val = HighlightColorValues.Yellow };
     DocumentFormat.OpenXml.Wordprocessing.Text runText = new DocumentFormat.OpenXml.Wordprocessing.Text() { Text = text };

     runPro.Append(highlight);
     HighLightRun.Append(runPro);
     HighLightRun.Append(runText);

     //insert the new created run part
     paragraph.InsertAfter(HighLightRun, runAfter);    
}

如果要突出显示 Run 中间的一些文本,则需要拆分 Run。所以用空字符串替换搜索文本是行不通的。

您的原始文本结构如下:

<Run>
    <Text>
        I am going to school
    </Text>
</Run>

如果你想突出显示going这个词,你需要用它做一个更复杂的结构:

<Run>
    <Text>
        I am 
    </Text>
</Run>
<Run>
    <Text>
        going
    </Text>
</Run>
<Run>
    <Text>
         to school
    </Text>
</Run>

然后中间的Run可以设置高亮

这是一个工作代码示例。请注意,此代码中没有错误处理!它应该让您了解如何解决您的任务。为生产使用实施适当的异常处理!

另请注意,此示例仅搜索第一次出现,因为它在您的代码中。如果您需要突出显示多个搜索匹配项,则必须改进此代码。

void HighLightText(Paragraph paragraph, string text)
{
    // Search for a first occurrence of the text in the text runs
    var found = paragraph
        .Descendants<Run>()
        .Where(r => !string.IsNullOrEmpty(r.InnerText) && r.InnerText != "\s")
        .Select(r =>
        {
            var runText = r.GetFirstChild<Text>();
            int index = runText.Text.IndexOf(text, StringComparison.OrdinalIgnoreCase);

            // 'Run' is a reference to the text run we found,
            // TextNode is a reference to the run's Text object,
            // 'TokenIndex` is the index of the search string in run's text
            return new { Run = r, TextNode = runText, TokenIndex = index };
        })                    
        .FirstOrDefault(o => o.TokenIndex >= 0);

    // Nothing found -- escape
    if (found == null)
    {
        return;
    }

    // Create a node for highlighted text as a clone (to preserve formatting etc)
    var highlightRun = found.Run.CloneNode(true);

    // Add the highlight node after the found text run and set up the highlighting
    paragraph.InsertAfter(highlightRun, found.Run);
    highlightRun.GetFirstChild<Text>().Text = text;
    RunProperties runPro = new RunProperties();
    Highlight highlight = new Highlight { Val = HighlightColorValues.Yellow };

    runPro.AppendChild(highlight);
    highlightRun.InsertAt(runPro, 0); 

    // Check if there's some text in the text run *after* the found text
    int remainderLength = found.TextNode.Text.Length - found.TokenIndex - text.Length;
    if (remainderLength > 0)
    {
        // There is some text after the highlighted section --
        // insert it in a separate text run after the highlighted text run
        var remainderRun = found.Run.CloneNode(true);
        paragraph.InsertAfter(remainderRun, highlightRun);  
        var textNode = remainderRun.GetFirstChild<Text>();
        textNode.Text = found.TextNode.Text.Substring(found.TokenIndex + text.Length);

        // We need to set up this to preserve the spaces between text runs
        textNode.Space = new EnumValue<SpaceProcessingModeValues>(SpaceProcessingModeValues.Preserve);
    }

    // Check if there's some text *before* the found text
    if (found.TokenIndex > 0)
    {
        // Something is left before the highlighted text,
        // so make the original text run contain only that portion
        found.TextNode.Text = found.TextNode.Text.Remove(found.TokenIndex);

        // We need to set up this to preserve the spaces between text runs
        found.TextNode.Space = new EnumValue<SpaceProcessingModeValues>(SpaceProcessingModeValues.Preserve);  
    }
    else
    {
        // There's nothing before the highlighted text -- remove the unneeded text run
        paragraph.RemoveChild(found.Run);
    }
}

此代码用于突出显示 I am going to school 句子中的 Igoingschool 单词。