使用 OpenXML 和 Regex 在 Word Docx 中查找和替换撇号(')的问题

Posted

技术标签:

【中文标题】使用 OpenXML 和 Regex 在 Word Docx 中查找和替换撇号(\')的问题【英文标题】:Issue with find and replace apostrophe( ' ) in a Word Docx using OpenXML and Regex使用 OpenXML 和 Regex 在 Word Docx 中查找和替换撇号(')的问题 【发布时间】:2020-02-25 03:27:50 【问题描述】:

Word 似乎使用了与 Visual Studio 不同的撇号字符,这导致使用 Regex 时出现问题。

我正在尝试使用 OpenXML 在 C# 中编辑一些 Word 文档。我基本上用公司名称替换​​ [[COMPANY]]。这一直很顺利,直到我遇到了名称以 s 结尾的公司的极端案例。我最终会遇到问题,有时它会创建一个 s。

示例: 公司名称:西蒙斯 Doc 中的文字:[[COMPANY]] 的业务是汽车。 结果:西蒙斯的生意是汽车。

这是不恰当的英语。

我应该能够像在 [[COMPANY]] 中那样使用基本的查找和替换,但它不起作用。

            Regex apostropheReplace = new Regex("s\\'s");
            docText = apostropheReplace.Replace(docText, "s\'"); 

这不是。似乎 Word 使用的字符和撇号(')与我在 Visual Studio 中使用键盘上的键时创建的标准字符不同。如果我使用键盘编写查找和替换,它将不起作用,但如果我从 Word 复制并粘贴撇号,它会起作用。

            Regex apostrophyReplace = new Regex("s\\’s");
            docText = apostrophyReplace.Replace(docText, "s\'"); 

注意第二个正则表达式中的不同字符。我对为什么会这样感到困惑,并且还想知道这是否是正确的做法。我尝试了“'”,但这不起作用。我只是想知道使用从 Word 复制的字符是否是正确的方法,是否有办法做到这一点,以便两个字符都可以工作,所以我对可能使用不同的文档创建的文档没有问题程序。

【问题讨论】:

有一些类型的引号字符,直引号或智能(弯)引号,就像你发现的那样,这些 ' 和 ' 是其中的一些:'' '' "" “” 您收到了两个非常好的答案。我只是想补充一点,Word 使用所谓的印刷引号,也称为“弯引号”。 Visual Studio 使用所谓的“打字机引号”或“直引号”。如答案中所述,这些是不同的 Unicode 字符,这意味着当您只提供直引号时,您的正则表达式与大引号不匹配。 【参考方案1】:

发生这种情况的原因是因为它们是不同的字符。

Word 实际上会在您键入一些标点字符后更改它们,以便为它们提供正确的倾向或改进演示。

我之前遇到过同样的问题,我用它作为正则表达式:[\u2018\u2019\u201A\u201b\u2032']

所以基本上将您的代码修改为:

Regex apostropheReplace = new Regex("s\\[\u2018\u2019\u201A\u201b\u2032']s");
docText = apostropheReplace.Replace(docText, "s\'")

我发现这是最常用的五种单引号和撇号。

如果您在使用双引号时遇到同样的问题,可以使用以下方法:[\u201C\u201D\u201E\u201F\u2033\u2036\"]

【讨论】:

谢谢!效果很好!我会投票,但这是我的第一篇 SO 帖子。 不用担心 - 很高兴它有帮助......一旦你知道如何做就很容易了:-p 欢迎来到 SO!【参考方案2】:

回答问题:

有没有办法让两个角色都能工作?

如果您希望一个 Regex 能够处理这两种情况,这可能是一个简单易读的解决方案:

 Regex apostropheReplace = new Regex("s\\['’]s");
 docText = apostropheReplace.Replace(docText, "s\'")

这具有额外的好处,即您试图涵盖两种撇号情况的其他开发人员可以理解。这种好处可以解决您问题的另一部分:

如果使用从 Word 中复制的字符是正确的做法?

这取决于您所说的“正确”是什么意思。如果您的意思是“其他开发人员最容易理解”,我会说是的,因为只需最少的查找量就可以准确地知道您的 Regex 正在寻找什么。如果您的意思是“最高性能”,那么这种简单的正则表达式搜索应该不是问题(可以找到一些不错的正则表达式性能提示 here)。

如果您的意思是“最通用/最强大的单引号正则表达式”,那么正如@Leonardo-Seccia 指出的那样,还有其他可能导致麻烦的字符编码。 (here 列出了一些常见的 Microsoft Word。)这样的解决方案可能如下所示:

Regex apostropheReplace =
    new Regex("s\\['\u2018\u2019\u201A\u201b]s");
docText = apostropheReplace.Replace(docText, "s\'")

但您当然可以根据需要添加其他字符编码。可以在here 找到更完整的字符编码列表 - 要将它们添加到上述正则表达式中,只需将“U+”更改为“u”并将其添加到另一个“\”字符之后的列表中。例如,要将“prime”符号(' 或 U+2032)添加到上面的列表中,请将 RegEx 字符串从

Regex("s\\['\u2018\u2019\u201A\u201b]s")

Regex("s\\['\u2018\u2019\u201A\u201b\u2032]s")

最终,您将根据您的用例判断哪些字符编码最“适合”包含在您的正则表达式中。

【讨论】:

谢谢!我会投票,但这是我的第一个 SO 帖子。上面的答案([\u2018\u2019\u201b\u2032']) 更适合一点,因为我想为所有用例做好准备。 不用担心 - 我很高兴你得到了答案,@mfontaine!我已经更新了我的答案以明确包含其他单引号编码,我提到可以添加这些编码。

以上是关于使用 OpenXML 和 Regex 在 Word Docx 中查找和替换撇号(')的问题的主要内容,如果未能解决你的问题,请参考以下文章

使用OpenXML操作Office文档

OpenXML - 将书签应​​用于 Word 文档中的段落

使用 OpenXML SDK 2.0 将页眉和页脚添加到现有的空 word 文档

使用openxml sdk 操作word 无法刷新域信息

在使用openXML生成word文档时,试图合并表格单元格。

dotnet OpenXML 聊聊文本段落对齐方式