RegEx Match VB.NET Выбрать чехол без дела

Я ищу RegEx, который найдет Select Case Statement, в которых нет Case Case Else.

Вот что я придумала до сих пор

(?sm)^\s*Select Case.*(?<!^\s*Case Else.*)End Select

Этот работает отлично, за исключением случаев, которые могут иметь вложенные операторы.

в моей попытке использовать балансовые группы, я пришел к следующему

Select Case(?>Select Case(?<DEPTH>)|End Select(?<-DEPTH>)|.?)*?(?(DEPTH)(?!))End Select

Который правильно находит сбалансированные группы Select Case/End Selects, но мне трудно заставить его работать с (?

Вот некоторые примеры данных:

Select Case
 Case :
  Select Case
   Case : Something
  End Select
  Case Else : SomethingElse
End Select

В этом случае он должен совпадать только с внутренним регистром выбора, потому что у ауттера есть его регистр.

Select Case
 Case :
  Select Case
   Case : Something
   Case Else : SomethingElse
  End Select
End Select

Должен совпадать с целым блоком, потому что у внутреннего есть иное, а у внешнего нет.

Select Case
 Case :
  Select Case
   Case : Something
   Case Else : SomethingElse
  End Select
  Case Else : SomethingElseOutter
End Select

Не должно совпадать, потому что как у внутреннего, так и у внешнего выбора есть другой случай

1 ответ

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'

Один лайнер:

^[ \t]*Select Case.*\n(?>(?>[ \t]*)(?>(?<nested>Select Case)|(?(nested)(?<-nested>End Select)?|(?!Case Else))).*\n)*?(?(nested)(?!)|[ \t]*End Select)

Тест на regexstorm.net


Описание

Регулярные совпадения Select Case и затем он пытается использовать как можно меньше строк, пока не найдет End Select, Для каждой строки:

  • Если есть вложенный Select CaseСоздает Захват в (?<nested>Select[ ]Case)
  • (?(nested)правда|ложный) является условием IF, которое:
    • Если есть захват для nested (т.е. внутри вложенного оператора), он может вычесть захват, когда (?<-nested>End[ ]Select)? совпадения (необязательная группа).
    • Или, если нет захвата (то есть в главном утверждении), строка не должна быть выражением Else (?!Case[ ]Else),

Это логика балансировки групп. Если это соответствует вложенному Select Case, он создает новый захват, и если он соответствует End Select это вычитает последний захват. Следовательно, только во внешней группе не будет сохраненных снимков.

Мы используем это в конце шаблона с (?(nested)(?!)|[ \t]*End[ ]Select), Если есть захват, он идет в (?!) (что никогда не может совпадать), дает сбой и возвращается, чтобы продолжать потреблять больше строк. Но если нет снимков, он может соответствовать [ \t]*End[ ]Select (или вернитесь назад и потребляйте больше строк).

Вот и все.

Однако обратите внимание, что если есть две позиции Select без Case Else, вложенные одна в другую, будет сопоставляться только внешнее утверждение. если вы заинтересованы в совпадении обоих, используйте

(?=(previous pattern))

и использовать Match.Groups(1) чтобы текст соответствовал.

Другие вопросы по тегам