2012-03-23 2 views
2

Вопрос:Regex для удаления одной строки SQL комментарии (-)

Может кто-нибудь дать мне рабочий регулярное выражение (C#/VB.NET), которые можно удалить одну строку комментарии из SQL заявления?

Я имею в виду эти комментарии:

-- This is a comment 

не те

/* this is a comment */ 

, потому что я уже могу обрабатывать звезды комментарии.

У меня есть сделал небольшой парсер, который удаляет эти замечания, когда они находятся в начале строки, но они также могут быть где-то после кода или хуже, в SQL-строку 'hello --Test -- World' Эти комментарии также должны быть удалены (за исключением строк в строке SQL, если это возможно).

Удивительно, но у меня не было регулярного выражения. Я бы предпочел, чтобы комментарии к звездам были более сложными, но на самом деле это не так.

В соответствии с запросом здесь мой код для удаления/**/- комментариев стиля (Чтобы игнорировать строки SQL-стиля, вы должны подставлять строки с уникальным идентификатором (я использовал 4 concinated), затем применим комментарий-удаление, а затем применить строковое 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 
+0

Что конечная цель здесь? Есть более эффективные инструменты для разбора языков ... –

+1

Как вы обрабатывали комментарии '/ ** /' в строках? –

+0

Остин Салонен: путем замены строк с помощью (фактически 4) уникальных идентификаторов, а затем удаления комментариев, а затем обратно-замены строк. –

ответ

6

Я разочарую всех вас. Это невозможно сделать с помощью регулярных выражений. Конечно, легко найти комментарии не в строке (что даже OP мог бы сделать), реальная сделка - это комментарии в строке. Существует небольшая надежда на look arounds, но этого все еще недостаточно. Говоря, что у вас есть предыдущая цитата в строке, она ничего не гарантирует. Единственное, что гарантирует вам кое-что, - это странность цитат. То, что вы не можете найти с регулярным выражением. Поэтому просто используйте подход с нерегулярным выражением.

EDIT: Вот 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 основан на трюке wierd SQL: 'this' является допустимой строкой.Даже две цитаты различаются. Если это неверно для вашего языка SQL, вы должны попробовать совершенно другой подход. Я тоже напишу программу, если это так, но это быстрее и проще.

+0

Я предполагаю, что это можно сделать с помощью регулярных выражений. Пожалуйста, проверьте мой ответ здесь: http://stackoverflow.com/a/33947706/3606250 – drizin

2

Вы хотите что-то подобное для простого случая

-{2,}.* 

The -. {2} ищет тир, что происходит 2 или более раз

. * Получает остальные линии до новой строки

* Но, для краевых случаев, оказывается, что SinistraD является правильным в том, что вы не можете поймать все, однако here is an article о том, как это может быть сделано в C# с комбинацией кода и регулярного выражения.

+0

Я не думаю, что это оставит только «привет-Тест-мир». – Kramii

+0

@Kramii Это исправлено. Я пропустил это. Кому-то, кто ниспослан, пожалуйста, повторите проверку, если вы все еще ищете :) –

+0

Закрыть, но вы пропустили случай, когда '' появляется в строке. Например, «WHERE name LIKE» - это не комментарий, но также будет соответствовать «.». – Kramii

0

Я не знаю, является ли регулярное выражение C#/VB.net особенным, но традиционно s/--.*// должно работать.

+0

Нет, это не делает различия между ' - '' внутри строкового литерала и вне его. –

0
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); 
} 

Давайте заменим, найти все строки, которые соответствуют тире тире комментарий и обратитесь к функции синтаксического анализа для каждого матча.

2

Это, кажется, хорошо работает для меня до сих пор; он даже игнорирует комментарии в строках, 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 комментария, а также -- стиля. Удалите |/\*(.|\n)*?\*/, чтобы избавиться от проверки /**/. Также be обязательно Вы используете опцию RegexOptions.IgnorePatternWhitespace Regex !!

Я тоже хотел иметь возможность обрабатывать двойные кавычки, но так как T-SQL их не поддерживает, вы также можете избавиться от |[""][^""]*[""].

Адаптировано из here.

Примечание (март 2015 г.): В конце концов, я закончил с использованием генератора парсера Antlr для этого проекта. Возможно, были некоторые крайние случаи, когда регулярное выражение не работало. В конце концов, я был намного уверен в результатах, использовавших Antlr, и это сработало хорошо.

0

В PHP, я использую этот код раскомментировать SQL (только одну строку):

$sqlComments = '@(([\'"`]).*?[^\\\]\2)|((?:\#|--).*?$)\s*|(?<=;)\[email protected]'; 
/* 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 to match MySQL comments

Смежные вопросы