我需要沿着批处理定界符边界拆分T-SQL脚本文件,并分别执行每个段。拆分很容易。GO语句必须在一行上单独存在,并且只能在空格之前和之后。(例外:GO也可以后面跟数字,而不是变量。我现在暂时忽略这种情况。现在我也忽略了GO之后插入注释的情况)
但是,可以在块注释内找到GO语句(显然会忽略它们)。沿该边界分裂将导致代码损坏。我想检查并拒绝脚本文件,如果它在块注释中包含GO语句。
到目前为止,我已经构建了此正则表达式:
(\/\*)(.?([^\*][^\/])*?)(^(\s*?)go(\s*?)$)(.?([^\/][^\*])*?)(?=(\*\/))
它几乎可以工作,但是仍然存在问题。
拆分和识别不符合要求的文件将在PowerShell中完成。
注意:在此阶段,我们尚未确定将使用解析器。可能的解析器选项仍在研究中
我在regex101.com上通过添加和删除字母进行了测试:
/*
llaa
GO
*/
GO
/*
a
*/
GO
a
/*
GOaaa
*/
a
GO
/*
a
*/
尝试以下正则表达式,仅$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
匹配行(^
)的开头,然后可能是空白的空格(\s*
),然后是文字go
(请注意,PowerShell的-match
运算符不区分大小写)。
(\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
andosql
工具和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 '^(.?([^*][^/])*?)$'
如上所示,只有否定的前瞻断言可以可靠地排除给定的(多字符)字符串。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句