正则表达式删除单行SQL注释( – )

题:

任何人都可以给我一个可以从SQL语句中删除单行注释的正则表达式(C#/ VB.NET)吗?

我的意思是这些评论:

-- This is a comment 

不是那些

 /* this is a comment */ 

因为我已经可以处理明星评论了。

我有一个小的解析器,当它们在行的开头时删除那些注释,但是它们也可以在代码之后或更糟的地方,在SQL字符串中'hello --Test -- World'这些注释也应该被删除(当然,除了SQL字符串中的那些 – 如果可能的话)。

令人惊讶的是,我没有使用正则表达式。 我会认为明星评论更难,但实际上,他们不是。

根据请求,这里我的代码删除/ ** / – 样式注释(为了让它忽略SQL样式字符串,你必须用uniqueidentifier替换字符串(我使用4个标准),然后应用注释删除,然后应用string-backsubstitution。

  static string RemoveCstyleComments(string strInput) { string strPattern = @"/[*][\w\d\s]+[*]/"; //strPattern = @"/\*.*?\*/"; // Doesn't work //strPattern = "/\\*.*?\\*/"; // Doesn't work //strPattern = @"/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*+/ "; // Doesn't work //strPattern = @"/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*+/ "; // Doesn't work // http://stackoverflow.com/questions/462843/improving-fixing-a-regex-for-c-style-block-comments strPattern = @"/\*(?>(?:(?>[^*]+)|\*(?!/))*)\*/"; // Works ! string strOutput = System.Text.RegularExpressions.Regex.Replace(strInput, strPattern, string.Empty, System.Text.RegularExpressions.RegexOptions.Multiline); Console.WriteLine(strOutput); return strOutput; } // End Function RemoveCstyleComments 

我会让你们所有人失望。 使用正则表达式无法做到这一点。 当然,很容易找到不在字符串中的注释(甚至OP也可以),真正的交易是字符串中的注释。 环顾四周有一点希望,但这仍然不够。 通过告诉你在一行中有一个前面的引用将不保证任何东西。 唯一可以保证你的东西的是引用的奇怪之处。 用正则表达式找不到的东西。 所以,只需采用非正则表达式方法。

编辑:这是c#代码:

  String sql = "--this is a test\r\nselect stuff where substaff like '--this comment should stay' --this should be removed\r\n"; char[] quotes = { '\'', '"'}; int newCommentLiteral, lastCommentLiteral = 0; while ((newCommentLiteral = sql.IndexOf("--", lastCommentLiteral)) != -1) { int countQuotes = sql.Substring(lastCommentLiteral, newCommentLiteral - lastCommentLiteral).Split(quotes).Length - 1; if (countQuotes % 2 == 0) //this is a comment, since there's an even number of quotes preceding { int eol = sql.IndexOf("\r\n") + 2; if (eol == -1) eol = sql.Length; //no more newline, meaning end of the string sql = sql.Remove(newCommentLiteral, eol - newCommentLiteral); lastCommentLiteral = newCommentLiteral; } else //this is within a string, find string ending and moving to it { int singleQuote = sql.IndexOf("'", newCommentLiteral); if (singleQuote == -1) singleQuote = sql.Length; int doubleQuote = sql.IndexOf('"', newCommentLiteral); if (doubleQuote == -1) doubleQuote = sql.Length; lastCommentLiteral = Math.Min(singleQuote, doubleQuote) + 1; //instead of finding the end of the string you could simply do += 2 but the program will become slightly slower } } Console.WriteLine(sql); 

这样做:找到每个评论文字。 对于每个,通过计算当前匹配与最后一个匹配之间的引号数来检查它是否在评论中。 如果这个数字是偶数,则它是一个注释,因此将其删除(找到行的第一行并删除它们之间的内容)。 如果它是奇数,这是在一个字符串中,找到字符串的结尾并移动到它。 Rgis片段基于一个奇怪的SQL技巧: ‘this’是一个有效的字符串 。即使这两个引号不同。如果你的SQL语言不正确,你应该尝试一种完全不同的方法。我会写一个程序到那个如果是这样的话,那么这个更快,更直接。

对于简单的情况,你想要这样的东西

 -{2,}.* 

– {2,}寻找发生2次或更多次的破折号

。*将其余行添加到换行符

*但是,对于边缘情况,似乎SinistraD是正确的,因为你无法捕捉到所有内容,但是这篇文章是关于如何在C#中使用代码和正则表达式的组合来完成的。

到目前为止,这似乎对我有用; 它甚至忽略了字符串中的注释, such as SELECT '--not a comment--' FROM ATable不是注释 – such as SELECT '--not a comment--' FROM ATable

  private static string removeComments(string sql) { string pattern = @"(?<=^ ([^'""] |['][^']*['] |[""][^""]*[""])*) (--.*$|/\*(.|\n)*?\*/)"; return Regex.Replace(sql, pattern, "", RegexOptions.IgnorePatternWhitespace | RegexOptions.Multiline); } 

注意:它旨在消除/**/ -style注释以及-- style。 删除|/\*(.|\n)*?\*/以删除/**/检查。 还要确保您使用的是RegexOptions.IgnorePatternWhitespace表达式选项!

我希望能够处理双引号,但由于T-SQL不支持它们,你也可以摆脱|[""][^""]*[""]

改编自这里 。

注意 (2015年3月):最后,我使用Antlr (一个解析器生成器)来完成这个项目。 可能有一些边缘情况,正则表达式不起作用。 最后,我对使用Antlr的结果更有信心,而且效果很好。

 Using System.Text.RegularExpressions; public static string RemoveSQLCommentCallback(Match SQLLineMatch) { System.Text.StringBuilder sb = new System.Text.StringBuilder(); bool open = false; //opening of SQL String found char prev_ch = ' '; foreach (char ch in SQLLineMatch.ToString()) { if (ch == '\'') { open = !open; } else if ((!open && prev_ch == '-' && ch == '-')) { break; } sb.Append(ch); prev_ch = ch; } return sb.ToString().Trim('-'); } 

代码

 public static void Main() { string sqlText = "WHERE DEPT_NAME LIKE '--Test--' AND START_DATE < SYSDATE -- Don't go over today"; //for every matching line call callback func string result = Regex.Replace(sqlText, ".*--.*", RemoveSQLCommentCallback); } 

让我们替换,找到所有与dash dash注释匹配的行,并为每个匹配调用解析函数。

我不知道C#/ VB.net正则表达式是否在某种程度上是特殊的,但传统上s/--.*//应该可行。

在PHP中,我使用此代码取消注释SQL(仅限单行):

 $sqlComments = '@(([\'"`]).*?[^\\\]\2)|((?:\#|--).*?$)\s*|(?<=;)\s+@ms'; /* Commented version $sqlComments = '@ (([\'"`]).*?[^\\\]\2) # $1 : Skip single & double quoted + backticked expressions |((?:\#|--).*?$) # $3 : Match single line comments \s* # Trim after comments |(?<=;)\s+ # Trim after semi-colon @msx'; */ $uncommentedSQL = trim( preg_replace( $sqlComments, '$1', $sql ) ); preg_match_all( $sqlComments, $sql, $comments ); $extractedComments = array_filter( $comments[ 3 ] ); var_dump( $uncommentedSQL, $extractedComments ); 

要删除所有注释,请参阅Regex以匹配MySQL注释