如何使用OpenXML高亮显示句子中的文本?

时间:2018-11-20 00:13:47

标签: c# openxml wordprocessingml

我正在使用以下代码搜索并突出显示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);    
}

1 个答案:

答案 0 :(得分:1)

如果要突出显示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句子中的goingschoolI am going to school单词。