Как я могу проверить, содержит ли файл T-SQL операторы GO внутри блочных комментариев, используя PowerShell? - PullRequest
0 голосов
/ 05 декабря 2018

Мне нужно разбить файлы сценариев T-SQL вдоль границы разделителя пакетов и выполнить каждый сегмент отдельно.Расщепить легко.Операторы GO должны быть одними в строке и могут предшествовать только после пробела.(Исключение: за GO также может следовать число, но не переменная. Пока я игнорирую этот случай. На данный момент я также игнорирую случай встроенного комментария после GO)

Однако операторы GO могутбыть найденным в комментариях блока (где они очевидно игнорируются).Расщепление вдоль этой границы приведет к нарушению кода.Я хочу проверить и отклонить файл сценария, если он содержит инструкцию GO внутри комментария блока.

До сих пор я построил это регулярное выражение:

(\/\*)(.?([^\*][^\/])*?)(^(\s*?)go(\s*?)$)(.?([^\/][^\*])*?)(?=(\*\/))

Он почти работает, но все равноимеет проблемы.

Разделение и выявление несовместимых файлов будет выполнено в PowerShell.

Примечание. На данном этапе установлено, что мы НЕ будем использовать парсер.Возможные параметры синтаксического анализатора все еще изучаются

Я тестировал на regex101.com, используя это, добавляя и удаляя буквы:

/*
llaa

GO


*/

GO

/*
a
*/

GO
a
/*

GOaaa

*/
a
GO

/*

a

*/

Ответы [ 2 ]

0 голосов
/ 06 декабря 2018

Мое предложение будет удалить комментарии, а затем разделить код.

0 голосов
/ 05 декабря 2018

Попробуйте следующее регулярное выражение, которое должно давать только $true, если найден внутренний комментарий GO;обратите внимание, что он также обнаруживает GO, за которым следует правильное (десятичное) число:

@'
/* a comment with GO, but not on its own line */

/* This GO should be found.
   GO 12  
*/

/* This one is outside a comment */
GO
'@ -match '(?sm)/[*](.(?![*]/))+?^\s*go(\s+\d+)?\s*$'

Вышеуказанное дает $true из-за наличия встроенного комментария GO 12.

  • (?sm) включает встроенные опции s (сделать . совпадением \n тоже) и m (сделать ^ и $ совпадением начала и конца строки тоже).

  • /[*] соответствует открытию комментария блока (* - метасимвол, который должен быть экранирован (\*) для интерпретациибуквально или указано внутри набора символов ([...]), как здесь).

  • (.(?![*]/))+? соответствует одному символу (.) , за которым не следует буквальный */ (с использованием (?!...), отрицательный взгляд), один или несколько раз (+), но без жадности (?).

    • Это ключ к сопоставлениюGO строка действительно только внутри комментария блока.
  • ^\s*go соответствует началу строки (^), за которым следуетвозможно пустой пробелace (\s*), за которым следует литерал go (обратите внимание, что оператор -match в PowerShell не учитывает регистр ).

  • (\s+\d+)? (необязательно) (?) соответствует непустому пробелу пробела (\s+), за которым следуют одна или несколько (+) цифр (\d).

  • \s*$ соответствует возможномупустой пробел до конца строки.

  • При условии, что все комментарии блока правильно сформированы, нет необходимости совмещать оставшуюся часть комментария.


Для выход за пределы отклонение нежелательного ввода , TheMadTechnician предлагает использовать -split, который может эффективно использоваться исключить те комментарии блока, в которые были введены GO строки из входных данных:

$sanitized = @'
/* a comment with GO, but not on its own line */
before
/* This GO should be found.
   GO 12  
*/
after
/* This one is outside a comment */
GO
...
/* Another comment with a GO.
  foo
GO
*/
last
'@ -split '(?sm)/[*](?:.(?![*]/))+?^\s*go(?:\s+\d+)?\s*$.+?[*]/' -join ''

В приведенном выше примере в переменной $sanitized хранится следующее:встроенные операторы GO пропали:

/* a comment with GO, but not on its own line */
before

after
/* This one is outside a comment */
GO
...

last

Если вы хотите сломать полученный скриптв составные партии оставшимися - некомментированными, эффективными - GO утверждениями :

$sanitized -split '(?m)^\s*go(?:\s+\d+)?\s*$'

Как вы указали, GO на самом деле не является частью T-SQL:

GO не является оператором Transact-SQL;это команда, распознаваемая утилитами sqlcmd и osql и редактором кода SQL Server Management Studio


Что касается того, что вы пытались :

Ваше подвыражение /\*(.?([^*][^/])*?)^\s*?go (упрощенное здесь), предназначенное для соответствия начала блочного комментария вплоть до встроенного GO, неэффективно для гарантии того, что подстрока */ не присутствует;он производит как ложные срабатывания, так и ложные отрицания.

Пример ложного срабатывания (соответствует, но не должен):

/*a*/
go

Пример ложного отрицания (не соответствует, но должен):

/*a*
go

Как вы и подозревали в комментарии, проблема в том, что [^*][^/] соответствует пара символов, поэтому поведение сопоставления в конечном итоге зависит от того, является ли количество входных символовнечетный или четный;используя упрощенные примеры:

# Even number of chars. -> $false, as intended
'*/' -match '^(.?([^*][^/])*?)$'

# Odd number of chars. -> $true(!)
'*/a' -match '^(.?([^*][^/])*?)$'

Только отрицательное прогнозное утверждение , как показано выше, может надежно исключить данную (многосимвольную) строку .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...