1

大きなデバイス構成ファイルがあり、RegEx を使用して、さらにコーディングするために関連部分を解析しようとしています... 解析しようとしている構成の部分は、「edit ServiceName ;mode」という単語で始まり、独自の行に「exit」という単語で終わります。この設定ファイルと返される文字列は複数行になります。特定のキーワードを含むこの構成ファイルの特定の部分のみを返すか一致させたい...

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 は貪欲なので、上記のルーチンは不要な部分を含む一致を返します。ルーチンを 2 つの別々の 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 パターンを作成せずにこれを機能させるには、最初のパターン マッチで何を変更する必要がありますか? 「exit」の最初のインスタンスの後に停止するように RegEx エンジンに明示的に指示するにはどうすればよいですか? どんな助けでも大歓迎です!ありがとうございました。

編集:マッチによって返されたいテスト文字列の部分を追加しました。「GoodMatch」セクションには、1 つ以上のキーワードを含めることができます。セクション全体を返す必要があります。

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)

これは、'edit ... 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))) は、その行の最後の改行から 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 に答える