I'm looking for a RegEx that will find Select Case Statements that have no Case Else in them.
Here's what I came up with so far
(?sm)^\s*Select Case.*(?<!^\s*Case Else.*)End Select
This one works perfectly except for cases that may have nested statements.
in my attempt to use balance groups, I came up with the following
Select Case(?>Select Case(?<DEPTH>)|End Select(?<-DEPTH>)|.?)*?(?(DEPTH)(?!))End Select
Which correctly finds balanced groups of Select Case/End Selects but I'm having a hard time getting it to work with the (?
Heres some sample data:
Select Case
Case :
Select Case
Case : Something
End Select
Case Else : SomethingElse
End Select
In this case it should match just the inner Select Case because the Outter has it's Case Else
Select Case
Case :
Select Case
Case : Something
Case Else : SomethingElse
End Select
End Select
Should match then entire block because the inner has the Else but the outter doesnt.
Select Case
Case :
Select Case
Case : Something
Case Else : SomethingElse
End Select
Case Else : SomethingElseOutter
End Select
Should not match because bo开发者_JS百科th inner and outter selects have a Case Else
Regex
^[ \t]*Select[ ]Case.*\n # Start of 'Select Case' statement
(?> # REPEAT as few as possible
(?>[ \t]*) # whitespace at beginning of line
(?> # And
(?<nested>Select[ ]Case) # there's a nested Select (+1 balancing group)
| # Or
(?(nested) # If inside a nested statement
(?<-nested>End[ ]Select)? # match 'End Select' (-1 balancing group)
| # Else
(?!Case[ ]Else) # it can't match a 'Case Else'
) #
) #
.*\n # Consume the whole line (go to next line)
)*? # END REPEAT
(?(nested)(?!)| # If inside a nested statement, it can't match
[ \t]*End[ ]Select) # if outer statement, match the 'End Select'
One-liner:
^[ \t]*Select Case.*\n(?>(?>[ \t]*)(?>(?<nested>Select Case)|(?(nested)(?<-nested>End Select)?|(?!Case Else))).*\n)*?(?(nested)(?!)|[ \t]*End Select)
Test on regexstorm.net
Description
The regex matches Select Case
and then it tries to consume as few lines as it can until it finds an End Select
. For each line:
- If there's a nested
Select Case
, it creates a Capture in(?<nested>Select[ ]Case)
(?(nested)
true|
false)
is an IF clause that:- If there's a capture for
nested
(i.e. inside a nested statement), it could substract a capture when(?<-nested>End[ ]Select)?
matches (optional group). - Or if there isn't a capture (i.e. in the main statement), the line should not be an Else statement
(?!Case[ ]Else)
.
- If there's a capture for
This is the logic behind balancing groups. If it matches a nested Select Case
, it creates a new capture, and if it matches an End Select
it substracts the last capture. Therefore, only in the outer group there will be no captures stored.
We use that at the end of the pattern with (?(nested)(?!)|[ \t]*End[ ]Select)
. If there's a capture it goes to (?!)
(which can never match), fails and backtracks to keep consuming more lines. But if there are no captures, it can match [ \t]*End[ ]Select
(or backtrack and consume more lines as well).
That's it.
Notice though that if there are two Select staments without a Case Else, nested one in another, only the outer statement will be matched. if you're interested in matching both, use
(?=(previous pattern))
and use Match.Groups(1)
to get the text matched.
精彩评论