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

C# 如何使用OpenXML突出显示句子中的文本?,c#,openxml,wordprocessingml,C#,Openxml,Wordprocessingml,我使用下面的代码搜索并突出显示MS Word文档中的文本,它适用于第1点,但不适用于第2点: 1. John Alter 我搜索Alter或John,它突出显示John/Alter-工作 2. I am going to school 我搜索去,它会突出显示去,但它会更改其顺序,因为我要去上学-不起作用 如何修复点2?下面是我的代码 private void HighLightText(Paragraph paragraph, string text) { string textO

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

1. John Alter 
我搜索
Alter
John
,它突出显示
John
/
Alter
-工作

2. I am going to school
我搜索
,它会突出显示
,但它会更改其顺序,因为
我要去上学
-不起作用

如何修复点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);    
}
private void HighLightText(段落,字符串文本)
{
string textOfRun=string.Empty;
var runCollection=段落.子体();
DocumentFormat.OpenXml.Wordprocessing.Run runAfter=null;
//查找包含字符的运行部件
foreach(DocumentFormat.OpenXml.Wordprocessing.Run在runCollection中运行)
{
如果(!string.IsNullOrWhiteSpace(段落.InnerText)&¶tion.InnerText!=“\\s”)
textOfRun=run.GetFirstChild().Text;
if(textOfRun.IndexOf(text,StringComparison.OrdinalIgnoreCase)>=0)
{    
//从此运行部件中删除角色
run.GetFirstChild().Text=Regex.Replace(textOfRun,Text,string.Empty,RegexOptions.IgnoreCase);//textOfRun.Replace(Text,string.Empty);
runAfter=运行;
打破
}    
}
//使用自定义字体和字符作为文本创建新的跑步记录
DocumentFormat.OpenXml.Wordprocessing.Run HighLightRun=new DocumentFormat.OpenXml.Wordprocessing.Run();
DocumentFormat.OpenXml.Wordprocessing.RunProperties runPro=新的DocumentFormat.OpenXml.Wordprocessing.RunProperties();
Highlight Highlight=new Highlight(){Val=HighlightColorValues.Yellow};
DocumentFormat.OpenXml.Wordprocessing.Text runText=newdocumentformat.OpenXml.Wordprocessing.Text(){Text=Text};
runPro.Append(突出显示);
HighLightRun.Append(runPro);
HighLightRun.Append(runText);
//插入新创建的管路零件
段落.插入后面(突出显示,突出显示);
}

< /代码> 如果您想在该代码的中间突出某些文本>运行< /代码>,则需要拆分<代码>运行<代码>。因此,用空字符串替换搜索文本将不起作用

您的原始文本结构如下所示:

<Run>
    <Text>
        I am going to school
    </Text>
</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);
    }
}
void HighLightText(段落、字符串文本)
{
//搜索文本运行中第一次出现的文本
var=段落
.后代()
.Where(r=>!string.IsNullOrEmpty(r.InnerText)&&r.InnerText!=“\\s”)
.选择(r=>
{
var runText=r.GetFirstChild();
int index=runText.Text.IndexOf(Text,StringComparison.OrdinalIgnoreCase);
//“Run”是对我们找到的文本Run的引用,
//TextNode是对运行的文本对象的引用,
//'TokenIndex'是run文本中搜索字符串的索引
返回新的{Run=r,TextNode=runText,TokenIndex=index};
})                    
.FirstOrDefault(o=>o.TokenIndex>=0);
//什么也没找到——逃跑
if(found==null)
{
返回;
}
//为高亮显示的文本创建一个节点作为克隆(以保留格式等)
var highlightRun=found.Run.CloneNode(true);
//在找到的文本运行后添加突出显示节点,并设置突出显示
段落.InsertAfter(highlightRun,find.Run);
highlightRun.GetFirstChild().Text=Text;
RunProperties runPro=新的RunProperties();
Highlight Highlight=newhighlight{Val=HighlightColorValues.Yellow};
runPro.AppendChild(高亮显示);
highlightRun.InsertAt(runPro,0);
//检查在找到的文本*之后*运行的文本中是否有一些文本
int remainderLength=found.TextNode.Text.Length-found.TokenIndex-Text.Length;
如果(剩余长度>0)
{
//突出显示的部分后面有一些文本--
//在高亮显示的文本运行后,将其插入单独的文本运行中
var remainderRun=found.Run.CloneNode(true);
段落.插入符(余数段、高亮段);
var textNode=remainderRun.GetFirstChild();
textNode.Text=found.textNode.Text.Substring(found.TokenIndex+Text.Length);
//我们需要设置此选项以保留文本运行之间的空格
textNode.Space=新的枚举值(SpaceProcessingModeValues.Preserve);
}
//检查在*找到的文本之前*是否有一些文本
如果(find.TokenIndex>0)
{
//在突出显示的文本之前留下了一些内容,
//因此,使原始文本只包含该部分
found.TextNode.Text=found.TextNode.Text.Remove(found.TokenIndex);
//我们需要设置此选项以保留文本运行之间的空格
found.TextNode.Space=新的枚举值(SpaceProcessingModeValues.Preserve);
}
其他的
{
//突出显示的文本之前没有任何内容--请删除不需要的文本
段落.RemoveChild(found.Run);
}
}

此代码用于突出显示
I
前进
,或者
学校
我要上学
句子中的单词。

@pfx:你能检查一下吗?你能添加文档以及任何其他代码让用户轻松重现你的问题吗?我已经在我的帖子中添加了代码,如果你需要文档,只需将我的第2点添加到代码-添加中,我就去sc
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);
    }
}