복붙노트

[SQL] 모두 일치하는 정규 표현식은 T-SQL 스크립트에 댓글

SQL

모두 일치하는 정규 표현식은 T-SQL 스크립트에 댓글

나는 T-SQL의 블록의 모든 주석을 캡처하는 정규 표현식이 필요합니다. 표현은 닷넷 정규식 클래스와 함께 작동하도록해야합니다.

이제 나는 다음과 T-SQL 있다고 가정 해 봅시다 :

-- This is Comment 1
SELECT Foo FROM Bar
GO

-- This is
-- Comment 2
UPDATE Bar SET Foo == 'Foo'
GO

/* This is Comment 3 */
DELETE FROM Bar WHERE Foo = 'Foo'

/* This is a
multi-line comment */
DROP TABLE Bar

나는 그들을 제거 할 수 있습니다 그래서, 멀티 라인 포함한 코멘트, 모두를 캡처해야합니다.

편집 : 그것은 모든하지만 주석을 취하는 식을 가지고 같은 목적을 제공합니다.

해결법

  1. ==============================

    1.이 작업을해야합니다 :

    이 작업을해야합니다 :

    (--.*)|(((/\*)+?[\w\W]+?(\*/)+))
    
  2. ==============================

    2.PHP에서, 나는 주석 SQL에 (이되는 주석 버전 -> X 수정을)이 코드를 사용하고 있습니다 :

    PHP에서, 나는 주석 SQL에 (이되는 주석 버전 -> X 수정을)이 코드를 사용하고 있습니다 :

    trim( preg_replace( '@
    (([\'"]).*?[^\\\]\2) # $1 : Skip single & double quoted expressions
    |(                   # $3 : Match comments
        (?:\#|--).*?$    # - Single line comment
        |                # - Multi line (nested) comments
         /\*             #   . comment open marker
            (?: [^/*]    #   . non comment-marker characters
                |/(?!\*) #   . not a comment open
                |\*(?!/) #   . not a comment close
                |(?R)    #   . recursive case
            )*           #   . repeat eventually
        \*\/             #   . comment close marker
    )\s*                 # Trim after comments
    |(?<=;)\s+           # Trim after semi-colon
    @msx', '$1', $sql ) );
    

    짧은 버전 :

    trim( preg_replace( '@(([\'"]).*?[^\\\]\2)|((?:\#|--).*?$|/\*(?:[^/*]|/(?!\*)|\*(?!/)|(?R))*\*\/)\s*|(?<=;)\s+@ms', '$1', $sql ) );
    
  3. ==============================

    3.이 코드를 사용 :

    이 코드를 사용 :

    StringCollection resultList = new StringCollection(); 
    try {
    Regex regexObj = new Regex(@"/\*(?>(?:(?!\*/|/\*).)*)(?>(?:/\*(?>(?:(?!\*/|/\*).)*)\*/(?>(?:(?!\*/|/\*).)*))*).*?\*/|--.*?\r?[\n]", RegexOptions.Singleline);
    Match matchResult = regexObj.Match(subjectString);
    while (matchResult.Success) {
        resultList.Add(matchResult.Value);
        matchResult = matchResult.NextMatch();
    } 
    } catch (ArgumentException ex) {
    // Syntax error in the regular expression
    }
    

    다음과 같은 입력으로 :

    -- This is Comment 1
    SELECT Foo FROM Bar
    GO
    
    -- This is
    -- Comment 2
    UPDATE Bar SET Foo == 'Foo'
    GO
    
    /* This is Comment 3 */
    DELETE FROM Bar WHERE Foo = 'Foo'
    
    /* This is a
    multi-line comment */
    DROP TABLE Bar
    
    /* comment /* nesting */ of /* two */ levels supported */
    foo...
    

    이러한 일치를 생성합니다 :

    -- This is Comment 1
    -- This is
    -- Comment 2
    /* This is Comment 3 */
    /* This is a
    multi-line comment */
    /* comment /* nesting */ of /* two */ levels supported */
    

    내 인생에서 내가 한 레벨이 사용보다 더 본 적이 있지만 이것은 단지, 중첩 된 주석의 2 개 수준을 일치하지 않는 것이. 이제까지.

  4. ==============================

    4.나는 일반 정규 expressons를 사용하여 모든 SQL 주석을 제거이 기능을했다. 및 블록 주석 (중첩 된 블록 주석이있는 경우에도) (A LINEBREAK 후이없는 경우에도)은 두 줄 주석을 제거합니다. (당신은 SQL 프로 시저 안에 뭔가를 검색 할 경우 유용하지만 당신은 문자열을 무시하려는)이 기능은 리터럴을 대체 할 수 있습니다.

    나는 일반 정규 expressons를 사용하여 모든 SQL 주석을 제거이 기능을했다. 및 블록 주석 (중첩 된 블록 주석이있는 경우에도) (A LINEBREAK 후이없는 경우에도)은 두 줄 주석을 제거합니다. (당신은 SQL 프로 시저 안에 뭔가를 검색 할 경우 유용하지만 당신은 문자열을 무시하려는)이 기능은 리터럴을 대체 할 수 있습니다.

    하지만, 더 중요한 것은 내가 블록 주석이 있기 때문에 (균형 그룹을 사용) 정규식 재 작성했다 - ""내 코드는 내가 "//"(으)로 변경 줄 주석에 있었다, 그래서 (C #을 코멘트에 관한 것입니다)이 답변에 기반 C #은하지 않지만 SQL은, 중첩 된 블록 주석을 수 있습니다.

    또한, 나는 대신 주석을 제거의 그냥 공백으로 의견을 채우고이 "preservePositions"인수를 가지고있다. 각 SQL 명령의 원래 위치를 유지하려면 그 경우에 당신은 원래 의견을 유지하면서 원래의 스크립트를 조작 할 필요가 유용합니다.

    Regex everythingExceptNewLines = new Regex("[^\r\n]");
    public string RemoveComments(string input, bool preservePositions, bool removeLiterals=false)
    {
        //based on https://stackoverflow.com/questions/3524317/regex-to-strip-line-comments-from-c-sharp/3524689#3524689
    
        var lineComments = @"--(.*?)\r?\n";
        var lineCommentsOnLastLine = @"--(.*?)$"; // because it's possible that there's no \r\n after the last line comment
        // literals ('literals'), bracketedIdentifiers ([object]) and quotedIdentifiers ("object"), they follow the same structure:
        // there's the start character, any consecutive pairs of closing characters are considered part of the literal/identifier, and then comes the closing character
        var literals = @"('(('')|[^'])*')"; // 'John', 'O''malley''s', etc
        var bracketedIdentifiers = @"\[((\]\])|[^\]])* \]"; // [object], [ % object]] ], etc
        var quotedIdentifiers = @"(\""((\""\"")|[^""])*\"")"; // "object", "object[]", etc - when QUOTED_IDENTIFIER is set to ON, they are identifiers, else they are literals
        //var blockComments = @"/\*(.*?)\*/";  //the original code was for C#, but Microsoft SQL allows a nested block comments // //https://msdn.microsoft.com/en-us/library/ms178623.aspx
        //so we should use balancing groups // http://weblogs.asp.net/whaggard/377025
        var nestedBlockComments = @"/\*
                                    (?>
                                    /\*  (?<LEVEL>)      # On opening push level
                                    | 
                                    \*/ (?<-LEVEL>)     # On closing pop level
                                    |
                                    (?! /\* | \*/ ) . # Match any char unless the opening and closing strings   
                                    )+                         # /* or */ in the lookahead string
                                    (?(LEVEL)(?!))             # If level exists then fail
                                    \*/";
    
        string noComments = Regex.Replace(input,
                nestedBlockComments + "|" + lineComments + "|" + lineCommentsOnLastLine + "|" + literals + "|" + bracketedIdentifiers + "|" + quotedIdentifiers,
            me => {
                if (me.Value.StartsWith("/*") && preservePositions)
                    return everythingExceptNewLines.Replace(me.Value, " "); // preserve positions and keep line-breaks // return new string(' ', me.Value.Length);
                else if (me.Value.StartsWith("/*") && !preservePositions)
                    return "";
                else if (me.Value.StartsWith("--") && preservePositions)
                    return everythingExceptNewLines.Replace(me.Value, " "); // preserve positions and keep line-breaks
                else if (me.Value.StartsWith("--") && !preservePositions)
                    return everythingExceptNewLines.Replace(me.Value, ""); // preserve only line-breaks // Environment.NewLine;
                else if (me.Value.StartsWith("[") || me.Value.StartsWith("\""))
                    return me.Value; // do not remove object identifiers ever
                else if (!removeLiterals) // Keep the literal strings
                    return me.Value;
                else if (removeLiterals && preservePositions) // remove literals, but preserving positions and line-breaks
                {
                    var literalWithLineBreaks = everythingExceptNewLines.Replace(me.Value, " ");
                    return "'" + literalWithLineBreaks.Substring(1, literalWithLineBreaks.Length - 2) + "'";
                }
                else if (removeLiterals && !preservePositions) // wrap completely all literals
                    return "''";
                else
                    throw new NotImplementedException();
            },
            RegexOptions.Singleline | RegexOptions.IgnorePatternWhitespace);
        return noComments;
    }
    

    테스트 1 (첫번째 원본, 다음 제거 의견, 지난 제거 의견 / 리터)

    [select /* block comment */ top 1 'a' /* block comment /* nested block comment */*/ from  sys.tables --LineComment
    union
    select top 1 '/* literal with */-- lots of comments symbols' from sys.tables --FinalLineComment]
    
    [select                     top 1 'a'                                               from  sys.tables              
    union
    select top 1 '/* literal with */-- lots of comments symbols' from sys.tables                   ]
    
    [select                     top 1 ' '                                               from  sys.tables              
    union
    select top 1 '                                             ' from sys.tables                   ]
    

    테스트 2 (첫번째 원래 다음 제거 의견, 지난 제거 의견 / 리터)

    Original:
    [create table [/*] /* 
      -- huh? */
    (
        "--
         --" integer identity, -- /*
        [*/] varchar(20) /* -- */
             default '*/ /* -- */' /* /* /* */ */ */
    );
                go]
    
    
    [create table [/*]    
    
    (
        "--
         --" integer identity,      
        [*/] varchar(20)         
             default '*/ /* -- */'                  
    );
                go]
    
    
    [create table [/*]    
    
    (
        "--
         --" integer identity,      
        [*/] varchar(20)         
             default '           '                  
    );
                go]
    
  5. ==============================

    5.이것은 나를 위해 작동합니다 :

    이것은 나를 위해 작동합니다 :

    (/\*(.|[\r\n])*?\*/)|(--(.*|[\r\n]))
    

    또는 * / .. * / 블록 내에 포함 - 그것은 모든 코멘트로 시작 일치

  6. ==============================

    6.나는 (Oracle 또는 MySQL의 반대)는 Microsoft SQL Server를 사용하고 참조하십시오. 당신이 정규식의 요구 사항을 완화하는 경우, 그것은 마이크로 소프트의 파서를 사용 (2012 년 이후) 지금 가능합니다 :

    나는 (Oracle 또는 MySQL의 반대)는 Microsoft SQL Server를 사용하고 참조하십시오. 당신이 정규식의 요구 사항을 완화하는 경우, 그것은 마이크로 소프트의 파서를 사용 (2012 년 이후) 지금 가능합니다 :

    using Microsoft.SqlServer.Management.TransactSql.ScriptDom;
    
    ...
    
    public string StripCommentsFromSQL( string SQL ) {
    
        TSql110Parser parser = new TSql110Parser( true );
        IList<ParseError> errors;
        var fragments = parser.Parse( new System.IO.StringReader( SQL ), out errors );
    
        // clear comments
        string result = string.Join ( 
          string.Empty,
          fragments.ScriptTokenStream
              .Where( x => x.TokenType != TSqlTokenType.MultilineComment )
              .Where( x => x.TokenType != TSqlTokenType.SingleLineComment )
              .Select( x => x.Text ) );
    
        return result;
    
    }
    

    SQL에서 댓글을 분리를 참조하십시오

  7. ==============================

    7.PG-작게하다,과 PostgreSQL을위한뿐만 아니라, MS-SQL에 대한뿐만 아니라 - 다음은 잘 작동합니다.

    PG-작게하다,과 PostgreSQL을위한뿐만 아니라, MS-SQL에 대한뿐만 아니라 - 다음은 잘 작동합니다.

    우리는 주석을 제거하면 아마도, 그 수단 스크립트는 더 이상 읽기, 동시에 그것을 축소에 대한없는 좋은 아이디어이다.

    그 라이브러리는 스크립트 축약의 일환으로 모든 댓글을 삭제합니다.

  8. from https://stackoverflow.com/questions/7690380/regular-expression-to-match-all-comments-in-a-t-sql-script by cc-by-sa and MIT license