【发布时间】:2017-06-02 23:59:14
【问题描述】:
众所周知,单词的查找和替换“通配符”功能受到一些严重的限制。
以下代码在 word 文档中实现了真正的正则表达式查找和替换,它的变体可在其他 Stackoverflow 和 SuperUser 问题中找到。
Sub RegEx_PlainText(Before As String, After As String)
Dim regexp As Object
Set regexp = CreateObject("vbscript.regexp")
With regexp
.Pattern = Before
.IgnoreCase = True
.Global = True
'could be any Range , .Range.Text , or selection object
ActiveDocument.Range = .Replace(ActiveDocument.Range, After)
End With
End Sub
但是,这会擦除所有格式的文档。
即使字符串长度相同或实际上是相同的字符串,Word 也不会逐个字符地保留格式,因此ActiveDocument.Range = ActiveDocument.Range 或Selection.Text=Selection.Text 将擦除所有格式(或更准确地说,将整个范围的格式设置为与范围内的第一个字符,并添加回车)。仔细想想,这种行为并不令人惊讶。
为了解决这个问题,以下代码运行正则表达式查找,然后循环遍历匹配项并仅在找到匹配项的范围内运行 .replace。 这样,只有在以下情况下才会丢失格式匹配本身有多种格式(例如,斜体字会丢失)
希望代码 cmets 使这变得非常透明。
Sub RegEx(Before As String, After As String, _
Optional CaseSensitive As Boolean = False, _
Optional Location As Range = Nothing, _
Optional DebugMode As Boolean = False)
'can't declare activedocument.range in parameters
If Location Is Nothing Then Set Location = ActiveDocument.Range
Dim regexp As Object
Dim Foundmatches As Object
Dim Match As Object
Dim MatchRange As Range
Dim offset As Integer: offset = 0
Set regexp = CreateObject("vbscript.regexp")
With regexp
.Pattern = Before
.IgnoreCase = Not CaseSensitive
.Global = True
'set foundmatches to collection of all regex matches
Set Foundmatches = .Execute(Location.text)
For Each Match In Foundmatches
'set matchrange to location of found string in source doc.
'offset accounts for change in length of document from already completed replacements
Set MatchRange = Location.Document _
.Range(Match.FirstIndex + offset, _
Match.FirstIndex + Match.Length + offset)
'debugging
If DebugMode Then
Debug.Print "strfound = " & Match.Value
Debug.Print "matchpoint = " & Match.FirstIndex
Debug.Print "origstrlength = " & Match.Length
Debug.Print "offset = " & offset
Debug.Print "matchrange = " & MatchRange.text
MatchRange.Select
Stop
Else
'REAL LIFE
'run the regex replace just on the range containing the regex match
MatchRange = .Replace(MatchRange, After)
'increment offset to account for change in length of document
offset = offset + MatchRange.End - MatchRange.Start - Match.Length
End If
Next
End With
End Sub
这适用于简单的文档,但是当我在真实文档上运行它时,matchrange 最终会出现在找到匹配项的位置附近,但并不完全正确。 不是可以预见的是,有时它在右边,有时在左边。通常文档越复杂。 (链接、上下文表、格式等)越错误。
有谁知道为什么这不起作用,以及如何解决它?如果我能理解为什么这不起作用,那么我可能能够确定这种方法是否可以修复,或者如果我只需要尝试不同的方法。
代码包含 DebugMode 参数,这意味着它只会循环遍历文档并突出显示所有匹配项,不执行任何更改。 还会向控制台输出一堆内容。这应该对任何愿意和我一起解决这个问题的人有所帮助。
https://calibre-ebook.com/downloads/demos/demo.docx这是一个可能有用的示例文档(不是我制作的)。
【问题讨论】:
-
你问的问题不清楚....
-
那么问题是如何在不破坏格式的情况下在 word 中进行正则表达式搜索。剩下的只是到目前为止我已经走了多远的代码,以及为什么它不起作用
-
非常有趣的问题
-
这里要考虑两件事:a) 为什么在 Word Find mehog 接受正则表达式时在 Word VBA 中使用 vbscript 正则表达式(尽管偶尔与“正常”正则表达式略有不同),以及 b) 替换单词会改变课程!我要做的是 a) 使用 Word 的 Find 方法 b) 考虑从文档的末尾开始向上以保留范围值。
-
@LocEngineer 不希望这个线程变成一个关于单词“正则表达式”与真正正则表达式的限制和缺点的长时间讨论,但很高兴在聊天中讨论它。足以说明单词的正则表达式不适用于各种目的。