如何使用PowerShell检查T-SQL文件是否在块注释内包含GO语句?

时间:2018-12-05 17:08:14

标签: regex powershell tsql

我需要沿着批处理定界符边界拆分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 :(得分:1)

请尝试以下正则表达式,如果找到内部注释$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(使^和{ {1}}也匹配的开始和结束)。

  • $匹配块注释的开头(/[*]是必须转义的元字符(*),以便从字面上解释或在字符集中指定({\*),如此处)。

  • [...]匹配单个字符((.(?![*]/))+?后面不跟文字. (使用*/,负前瞻) ,一次或多次((?!...)),但非贪婪(+)。

    • 这是仅在块注释内 匹配?行的关键。
  • GO匹配行的开头(^\s*go),然后是空白的空格(^),然后是文字\s*(请注意,PowerShell的go运算符不区分大小写 )。

  • -match可选((\s+\d+)?)匹配非空白空格(?),后跟一个或多个(\s+)数字({{1} })。

  • +匹配到行尾的空白行。

  • 假设所有块注释的格式正确,则无需匹配其余注释。


对于不只是拒绝不必要的输入TheMadTechnician建议使用\d,它可以有效地 从输入中消除嵌入了\s*$的那些块注释:

-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 isn't actually a part of T-SQL

  

GO不是Transact-SQL语句;它是$sanitized -split '(?m)^\s*go(?:\s+\d+)?\s*$' GO实用程序以及SQL Server Management Studio代码编辑器所识别的命令


关于您尝试过的事情

您的sqlcmd子表达式(此处简化)旨在将块注释的开头与嵌入式osql匹配,在确保子串/\*(.?([^*][^/])*?)^\s*?go不是上无效 em>存在;它会同时产生误报和误报。

误报的示例(匹配,但不应该):

GO

否定否定示例(不匹配,但应该匹配):

*/

正如您在评论中所怀疑的那样,问题在于/*a*/ go 与字符的匹配,因此匹配行为最终取决于输入字符的数量是奇数还是偶数。使用简化的示例:

/*a*
go

只有否定超前断言(如上所示)才能可靠地排除给定的(多字符)字符串

答案 1 :(得分:0)

我的建议是删除注释,然后拆分代码。