如何使用C# .NET替换Word文档中含换行的{{}}包裹文本?
C#替换Word中{{}}包裹文本失败的解决办法
问题场景
Word文档中有如下内容:
This is a test
{{3.3 iwanttochangethis}}
使用OpenXML SDK读取时,目标文本被拆分成多个独立的<w:t>节点,内容变成:
This is a test
{{
3.3
i
want
to
change
this
}}
原代码直接遍历单个<w:t>节点,只能匹配未被拆分的文本,尝试换行替换、正则匹配均无效。
问题根源
Word的OpenXML格式会根据排版规则(自动换行、格式变化等)将连续文本分割为多个<w:t>节点,每个节点对应一小段文本。直接处理单个节点无法匹配跨节点的完整{{}}包裹内容。
解决方案
方法一:合并相邻文本节点后替换
先将同一段落内的相邻文本节点合并,确保完整的{{}}内容在同一个<w:t>节点中,再进行正则替换,适合需要保留原格式的场景:
using (WordprocessingDocument doc = WordprocessingDocument.Open(outputPath, true)) { var body = doc.MainDocumentPart.Document.Body; // 遍历所有段落,合并相邻Run的Text内容 foreach (var para in body.Descendants<Paragraph>()) { var runs = para.Descendants<Run>().ToList(); // 从后往前合并,避免索引错乱 for (int i = runs.Count - 1; i > 0; i--) { var currentRun = runs[i]; var prevRun = runs[i - 1]; var currentText = currentRun.Descendants<Text>().FirstOrDefault(); var prevText = prevRun.Descendants<Text>().FirstOrDefault(); if (currentText != null && prevText != null) { prevText.Text += currentText.Text; currentRun.Remove(); } } } // 正则替换所有{{}}包裹的内容 foreach (var textNode in body.Descendants<Text>()) { textNode.Text = Regex.Replace(textNode.Text, @"\{\{([\s\S]*?)\}\}", match => { // 根据捕获的内容自定义替换逻辑 var innerContent = match.Groups[1].Value.Trim(); if (innerContent.StartsWith("3.3")) { return "To this"; } // 其他内容保留原格式 return match.Value; }); } doc.MainDocumentPart.Document.Save(); }
方法二:按段落拼接文本后重新生成节点
直接拼接段落内所有文本内容,替换后重新生成节点,操作简单但会丢失段落内的局部格式,适合无需保留格式的场景:
using System.Text.RegularExpressions; using DocumentFormat.OpenXml.Packaging; using DocumentFormat.OpenXml.Wordprocessing; // ... using (WordprocessingDocument doc = WordprocessingDocument.Open(outputPath, true)) { var body = doc.MainDocumentPart.Document.Body; foreach (var para in body.Descendants<Paragraph>().ToList()) { // 拼接段落内所有文本 string fullParaText = string.Join("", para.Descendants<Text>().Select(t => t.Text)); // 执行替换 string replacedText = Regex.Replace(fullParaText, @"\{\{([\s\S]*?)\}\}", match => { if (match.Groups[1].Value.Contains("3.3 iwanttochangethis")) { return "To this"; } return match.Value; }); // 清空原段落内容,添加新文本 para.RemoveAllChildren<Run>(); para.Append(new Run(new Text(replacedText))); } doc.MainDocumentPart.Document.Save(); }
注意事项
- 方法一中,若段落内存在格式差异(如部分文本加粗),合并后会丢失局部格式,需根据实际场景调整合并逻辑;
- 正则表达式
@"\{\{([\s\S]*?)\}\}"中的[\s\S]可以匹配包括换行在内的任意字符,确保能匹配跨换行的{{}}内容; - 操作完成后务必调用
Save()方法保存文档修改。
内容的提问来源于stack exchange,提问作者Nopidity
相关产品推荐
相关产品推荐

