Попробуйте следующее регулярное выражение, которое должно давать только $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 '^(.?([^*][^/])*?)$'
Только отрицательное прогнозное утверждение , как показано выше, может надежно исключить данную (многосимвольную) строку .