1

我有一个大型设备配置文件,我正在尝试使用 RegEx 解析出相关部分以进行进一步编码......我尝试解析的配置部分将以“edit ServiceName ;mode”和将在其自己的行上以“退出”一词结尾。此配置文件和返回的字符串将位于多行。我只想返回或匹配此配置文件中包含某些关键字的某些部分...

Sub TestRegEx_1()
Dim TestString
Dim objRegEx, f_objResults, f_Match

TestString = "edit NonMatch1 ;mode" & vbCrLf & _
    "Something Random" & vbCrLf & "Something Random" & vbCrLf & _
    "exit" & vbCrLf & _
    "edit NonMatch2 ;mode" & vbCrLf & _
    "Something Random" & vbCrLf & _
    "exit" & vbCrLf & _
    "edit GoodMatch1 ;mode" & vbCrLf & _
    "Something Random" & vbCrLf & "Something Random" & vbCrLf & _
    "KeyWord_1 1 2 and 3" & vbCrLf & _
    "exit" & vbCrLf & _
    "edit GoodMatch2 ;mode" & vbCrLf & _
    "KeyWord_2 A B and C" & vbCrLf & _
    "Something Random" & vbCrLf & "Something Random" & vbCrLf & _
    "exit" & vbCrLf & _
    "edit NonMatch3 ;mode" & vbCrLf & _
    "Something Random" & vbCrLf & "Something Random" & vbCrLf & _
    "exit" & vbCrLf & _
    "edit GoodMatch3 ;mode" & vbCrLf & _
    "Something Random" & vbCrLf & "Something Random" & vbCrLf & _
    "KeyWord_3 1A" & vbCrLf & _
    "Something Random" & vbCrLf & "Something Random" & vbCrLf & _
    "exit"

Set objRegEx = CreateObject("VBScript.RegExp")
objRegEx.IgnoreCase = True
objRegEx.MultiLine = True
objRegEx.Global = True

objRegEx.Pattern = "^edit (.{0,}) \;mode[\s\S]*?" & _
 "(?=(KeyWord_1|KeyWord_2|KeyWord_3))[\s\S]*?exit$"

Set f_objResults = objRegEx.Execute(TestString)
For Each f_Match In f_objResults
    MsgBox f_Match.Value
Next
End Sub

因为 RegEx 是贪婪的,所以上面的例程将返回一个包含我不想要的部分的匹配项。我能够将我的例程拆分为两个单独的 RegEx 模式搜索以使其正常运行,但我想修改我的初始模式搜索,这样我就不必这样做了。下面的例程将创建我正在寻找的输出。

Sub TestRegEx_2()
Dim TestString
Dim objRegEx, f_objResults, f_Match

TestString = "edit NonMatch1 ;mode" & vbCrLf & _
    "Something Random" & vbCrLf & "Something Random" & vbCrLf & _
    "exit" & vbCrLf & _
    "edit NonMatch2 ;mode" & vbCrLf & _
    "Something Random" & vbCrLf & _
    "exit" & vbCrLf & _
    "edit GoodMatch1 ;mode" & vbCrLf & _
    "Something Random" & vbCrLf & "Something Random" & vbCrLf & _
    "KeyWord_1 1 2 and 3" & vbCrLf & _
    "exit" & vbCrLf & _
    "edit GoodMatch2 ;mode" & vbCrLf & _
    "KeyWord_2 A B and C" & vbCrLf & _
    "Something Random" & vbCrLf & "Something Random" & vbCrLf & _
    "exit" & vbCrLf & _
    "edit NonMatch3 ;mode" & vbCrLf & _
    "Something Random" & vbCrLf & "Something Random" & vbCrLf & _
    "exit" & vbCrLf & _
    "edit GoodMatch3 ;mode" & vbCrLf & _
    "Something Random" & vbCrLf & "Something Random" & vbCrLf & _
    "KeyWord_3 1A" & vbCrLf & _
    "Something Random" & vbCrLf & "Something Random" & vbCrLf & _
    "exit"

Set objRegEx = CreateObject("VBScript.RegExp")
objRegEx.IgnoreCase = True
objRegEx.MultiLine = True
objRegEx.Global = True

'This Works...
objRegEx.Pattern = "^edit (.{0,}) \;mode[\s\S]*?exit$"
Set f_objResults = objRegEx.Execute(TestString)

objRegEx.Pattern = "(?=(KeyWord_1|KeyWord_2|KeyWord_3))"
For Each f_Match In f_objResults
    If objRegEx.test(f_Match.Value) Then
        MsgBox f_Match.Value
    End If
Next

End Sub

我需要对我的初始模式匹配进行哪些更改才能使其工作而无需创建单独的 RegEx 模式?如何明确告诉 RegEx 引擎在“exit”的第一个实例之后停止,以便如果它没有找到匹配项,它不会继续包含其他字符串,直到找到匹配项?任何帮助是极大的赞赏!谢谢你。

编辑:添加了我希望匹配返回的测试字符串中的部分。“GoodMatch”部分可以包含一个或多个关键字。我需要返回完整的部分。

edit GoodMatch1 ;mode
Something Random
Something Random
KeyWord_1 1 2 and 3
exit

edit GoodMatch2 ;mode
KeyWord_2 A B and C
Something Random
Something Random
exit

edit GoodMatch3 ;mode
Something Random
Something Random
KeyWord_3 1A
Something Random
Something Random
exit
4

3 回答 3

4

我不确定您的完整配置文件如何,但您可以尝试以下操作:

(KeyWord_1|KeyWord_2|KeyWord_3)(?=(?:(?!edit)[\s\S])*?exit)

这将仅在“编辑...退出”块内匹配。

或者:

(KeyWord_1|KeyWord_2|KeyWord_3)(?=(?:(?!edit[^;]+;mode )[\s\S])*?exit)

对于特定的 'edit ... ;mode ... exit' 块。

前瞻是强制匹配在“编辑...退出”块内的原因,基本上是通过确保在下一个“退出”之前没有“编辑”。如果您在一个块内,则两者之间不会有“编辑”,因此会有匹配。如果你在外面,你一定会在“退出”之前点击“编辑”,因此不匹配。


编辑:要获得整个块,您可以使用:

edit(?=(?:(?!exit)[\S\s])*\b(KeyWord_1|KeyWord_2|KeyWord_3)\b)(?:(?!exit)[\S\s])*exit

匹配本身是块,子匹配是关键字。

于 2013-10-07T21:29:42.173 回答
1

您的正则表达式并不贪心,但您已成为对非贪心匹配的常见误解的受害者。那些不会产生最短的匹配,而是从当前光标位置到非贪婪(子)表达式之后的表达式的下一个匹配项。

让我们看一下(部分)您的测试字符串:

edit NonMatch1 ;mode
Something Random
Something Random
exit
edit NonMatch2 ;mode
Something Random
exit
edit GoodMatch1 ;mode
Something Random
Something Random
KeyWord_1 1 2 and 3
exit
edit GoodMatch2 ;mode
KeyWord_2 A B and C
Something Random
Something Random
exit

你想要的第一场比赛是这样的:

edit NonMatch1 ;mode
Something Random
Something Random
exit
edit NonMatch2 ;mode
Something Random
exit
edit GoodMatch1 ;mode
Something Random
Something Random
KeyWord_1 1 2 and 3
exit
edit GoodMatch2 ;mode
KeyWord_2 A B and C
Something Random
Something Random
exit

但你实际得到的是:

edit NonMatch1 ;mode
Something Random
Something Random
exit
edit NonMatch2 ;mode
Something Random
exit
edit GoodMatch1 ;mode
Something Random
Something Random
KeyWord_1 1 2 and 3
exit
edit GoodMatch2 ;mode
KeyWord_2 A B and C
Something Random
Something Random
exit

这样做的原因是当正则表达式解析器开始读取您的字符串时,第一行匹配您的表达式的第一部分 ( ^edit (.{0,}) \;mode)。然后,表达式 ( ) 的下一部分[\s\S]*?(?=(KeyWord_1|KeyWord_2|KeyWord_3))匹配从该行末尾的换行符到您的三个关键字之一的第一次出现的所有内容,从而跨越几个edit部分。

解决您的问题的最简单方法可能是使用正则表达式将字符串不加选择地划分为编辑部分,然后使用字符串匹配来选择您想要的部分:

testString = "..."

Set re = New RegExp
re.IgnoreCase = True
re.MultiLine  = True
re.Global     = True
re.Pattern    = "^edit (.*) \;mode[\s\S]*?exit$"

For Each m In re.Execute(testString)
  If InStr(m.Value, "KeyWord_1") > 0 Then
    'do some
  ElseIf InStr(m.Value, "KeyWord_2") > 0 Then
    'do other
  ElseIf InStr(m.Value, "KeyWord_3") > 0 Then
    'do something completely different
  End If
Next

当然你也可以在循环中使用另一个正则表达式:

testString = "..."

Set re = New RegExp
re.IgnoreCase = True
re.MultiLine  = True
re.Global     = True
re.Pattern    = "^edit (.*) \;mode[\s\S]*?exit$"

Set keywords = New RegExp
keywords.IgnoreCase = True
keywords.Pattern    = "keyword_1|keyword_2|keyword_3"

For Each m In re.Execute(testString)
  If keywords.Test(m.Value) Then
    WScript.Echo m.Value
  End If
Next
于 2013-10-07T21:29:56.383 回答
0

你需要懒惰,这是?。

http://www.regular-expressions.info/repeat.html

于 2013-10-07T19:46:45.110 回答