【问题标题】:Excel VBA nested regex replaceExcel VBA嵌套正则表达式替换
【发布时间】:2019-11-14 16:31:30
【问题描述】:

是否可以在 Excel VBA 中嵌套正则表达式替换函数和/或作为单元格公式?

例如,我有以下文本:“Lorem [ipsum dolor sit] amet, [consetetur sadipscing] elitr。” (注意方括号)

是否有可能将其转换为:“Lorem ipsum_dolor_sit amet, consetetur_sadipscing elitr.”?

所以我想:

  1. 找到方括号内的所有术语
  2. 在其中:替换 所有带下划线的空格
  3. 去掉方括号

并通过这些替换返回整个句子。

以我目前的尝试,我只能删除括号:

Function RegexReplace(...)
...
Set oRegex = CreateObject("VBScript.RegExp")
oRegex.Pattern = "\[([^\[\]]*)\]"
oRegex.Replace(strInput, "$1")
...

并将此函数作为公式嵌套在单元格中或代码oRegex.Replace(strInput, Replace("$1", " ", "_") 中似乎是不可能的,因为嵌套替换函数Replace(.. 在评估替换字符串$1 之前被调用,因此没有空白替换。

任何解决方案的建议?谢谢:-)

【问题讨论】:

  • 你看过this answer吗?
  • 如果没有[],是否要添加空格?喜欢a [ b c -> a [ b_c?或者a b]c => a_b]c?
  • @PeterT:是的,我看了一下,但我不明白这些信息如何帮助解决我的问题。有什么关于嵌套替换的吗?
  • @WiktorStribiżew:如果没有括号,我不想替换任何东西。但是对于一对打开和关闭的括号,我想用里面的 unsercores 替换空白并删除括号。仅打开或仅关闭,甚至嵌套括号都没有用例。

标签: regex excel vba


【解决方案1】:

另一种解决方案是在每个循环中执行正则表达式,并且只获取第一个匹配项并为此更新结果。因此每个循环都会更新字符索引,您可以使用任何更改字符数的替换。 这里我也使用了子匹配,即没有括号(参见模式)。

Function RegexReplace(cell As Variant) As String
Dim oRegex As Object, m As Object
Dim strMatch As String

Set oRegex = CreateObject("VBScript.RegExp")
With oRegex
    .Pattern = "\[([^\[\]]*)\]"
    .Global = False
End With
RegexReplace = cell.Text
Do While oRegex.Test(RegexReplace)
    Set allMatches = oRegex.Execute(RegexReplace)
    Set FirstMatch = allMatches(0)
    strMatch = Replace(FirstMatch.SubMatches(0), " ", "_")
    RegexReplace = Left(RegexReplace, FirstMatch.FirstIndex) & strMatch & Mid(RegexReplace, FirstMatch.FirstIndex + Len(FirstMatch.Value) + 1)
    DoEvents
Loop

End Function

【讨论】:

    【解决方案2】:

    如果您修改代码,则可以将匹配项中的所有空格替换为下划线

    Function RegexReplace(cell As Variant) As String
    Dim oRegex As Object, m As Object, offset As Long
    Set oRegex = CreateObject("VBScript.RegExp")
    offset = 0
    With oRegex
        .Pattern = "\[([^[\]]*)]"
        .Global = True
    End With
    RegexReplace = cell.Text
    For Each m In oRegex.Execute(RegexReplace)
        RegexReplace = Left(RegexReplace, m.FirstIndex - offset) & Replace(m.SubMatches(0), " ", "_") & Mid(RegexReplace, m.FirstIndex + 1 + Len(m.Value) - offset)
        offset = offset + 2
    Next m
    End Function
    

    \[([^[\]]*)] 模式将匹配 [,然后将除 [] 之外的零个或多个字符捕获到第 1 组中,然后仅匹配 ]。然后,使用For Each m In oRegex.Execute(RegexReplace) 遍历所有匹配项,一旦找到匹配项,匹配前的子字符串、替换空格的匹配项(使用Replace(m.Submatches(0), " ", "_"))和匹配后的文本连接起来形成函数输出。

    【讨论】:

    • 您的代码会生成一个包含括号的文本,所以如果我简单地删除 RegexReplace = Replace(RegexReplace, "[", "") RegexReplace = Replace(RegexReplace, "]", "") 的所有括号(在 for 循环之后),它就可以工作。但是,如果我尝试在 for 循环中删除这些括号,这会变得更加复杂,因为我会更改字符数。所以使用m.FirstIndex 依赖于原始字符串,而不是每个循环中更改的字符串。非常感谢您的解决方案!
    • @MI285 已修复,添加偏移后即可正常使用。
    • 谢谢,也是另一种解决方案。可能比每个循环执行正则表达式更快。
    猜你喜欢
    • 1970-01-01
    • 2019-01-08
    • 2014-04-18
    • 1970-01-01
    • 1970-01-01
    • 2019-02-28
    • 2018-03-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多