2016-03-21 9 views
0

Ich versuche, eine VBA Regex zu schreiben, um Kommentare aus Teradata SQL-Textdateien zu entfernen.VBA-Regex, um Kommentare aus Teradata SQL-Textdateien zu entfernen

Es gibt zwei Arten von Kommentaren:

1 - Das Auftreten von zwei Strichen, '-' bezeichnet den Rest der Zeile als Kommentare.

2./* xxx */ Alles zwischen '/ *' und '* /' ist Kommentare. Kommentare dieses Typs können über 1+ Zeilen verteilt werden.

Die Komplikation ist mit Text in einfachen Anführungszeichen wie ‚--Diese Striche in Apostrophe sind so ausbleiben Kommentare bezeichnen kann‘.

Ich bin neu bei Regex und der Versuch, dies herauszufinden, erweist sich als über mich hinaus. Ich habe nach dem Vorbild des negativen Lookahead gedacht.

Kann mir bitte jemand helfen?

Dies ist so weit, wie ich bekommen haben:

Typ 1:

\ - \ - [\ S \ t] * $

Typ 2:

/\ * [\ s \ S] *? \ */

+1

Können Sie Beispiele mit Eingang und erwartete Ausgabe hinzufügen? –

+0

Im Allgemeinen können Sie dies nicht mit regulären Ausdrücken tun. Sie müssen einen SQL-Parser irgendeiner Art verwenden. Ähnliche Frage hier: http://stackoverflow.com/questions/9842991/regex-to-remove-single-line-sql-comments. –

+0

Ich würde lieber VBA üblichen String-Processing-Funktionen für diese Aufgabe verwenden ... – dnep

Antwort

0

Ein auf rekursiven Parseraufrufen basierender Algorithmus. Es gibt verschiedene Modi: Kommentare von 3 Untertypen, Parsing in Anführungszeichen, in Anführungszeichen und normal. Der normale Modus kann durch jeden anderen Modus geändert werden, der wiederum der einzige Normalmodus wird. Also e. G. Anführungszeichen innerhalb von Kommentaren und Kommentarzeichen innerhalb von Text in Anführungszeichen werden ignoriert. Die zu durchsuchenden Zeichen hängen vom aktuellen Modus ab. Die Quelle wird chunkweise geparst, sobald die Zielzeichen gefunden sind, wird der Modus umgeschaltet, der aktuelle Abschnitt ist beendet und der nächste beginnt mit dem nächsten rekursiven Aufruf. Call Stack speichert transiente Ergebnisse. Nachdem die Quelle beendet ist, startet der Rückwärtsprozess und jeder aufgerufene Parser verkettet und gibt seinen Chunk zurück, sodass schließlich ein vollständiger Code abgerufen wird. Hier

ist der Code:

Option Explicit 

Sub RemoveComments() 

    Dim strOriginal As String 
    Dim strProcessed As String 

    strOriginal = ReadTextFile("C:\Users\DELL\Desktop\tmp\source.sql", 0) ' -2 - System default, -1 - Unicode, 0 - ASCII 
    Parse strOriginal, strProcessed, 0 
    WriteTextFile strProcessed, "C:\Users\DELL\Desktop\tmp\result.sql", 0 

End Sub 

Sub Parse(strSrc As String, strRes As String, lngMode As Long) 

    Static objRegExp As Object 
    Dim strBeg As String 
    Dim objMatches As Object 
    Dim lngPos As Long 
    Dim lngEscPos As Long 
    Dim strRet As String 

    If objRegExp Is Nothing Then ' initialize regexp once 
     Set objRegExp = CreateObject("VBScript.RegExp") 
     With objRegExp 
      .Global = False 
      .MultiLine = True 
      .IgnoreCase = True 
     End With 
    End If 
    strRes = "" 
    If strSrc = "" Then Exit Sub ' source completed 
    strBeg = "" ' preceding chunk is empty by default 
    Select Case lngMode 
     Case 0 ' processing normal 
      With objRegExp 
       .Pattern = "(\/\*)|(^[ \t]*--)|(--)|(\')" 
       Set objMatches = .Execute(strSrc) 
       If objMatches.Count = 0 Then 
        strRes = strSrc 
        Exit Sub ' source completed 
       End If 
       lngPos = objMatches(0).FirstIndex 
       With objMatches(0) 
        Select Case True 
         Case .SubMatches(0) <> "" 
          lngMode = 1 ' start multiline comment 
         Case .SubMatches(1) <> "" 
          lngMode = 2 ' start whole line comment 
         Case .SubMatches(2) <> "" 
          lngMode = 3 ' start singleline comment 
         Case .SubMatches(3) <> "" 
          lngMode = 4 ' start text in quotes 
          lngPos = lngPos + 1 ' skip found quote char 
        End Select 
       End With 
      End With 
      strBeg = Left(strSrc, lngPos) 
      lngPos = lngPos + 1 
     Case 1 ' processing multiline comment 
      lngMode = 0 ' start normal 
      lngPos = InStr(strSrc, "*/") 
      If lngPos = 0 Then Exit Sub ' source completed, comment unclosed 
      lngPos = lngPos + 2 ' skip comment closing char 
     Case 2 ' processing whole line comment 
      lngMode = 0 ' start normal 
      lngPos = InStr(strSrc, vbCrLf) 
      If lngPos = 0 Then Exit Sub ' source completed 
      lngPos = lngPos + 2 ' skip new line char 
     Case 3 ' processing singleline comment 
      lngMode = 0 ' start normal 
      lngPos = InStr(strSrc, vbCrLf) 
      If lngPos = 0 Then Exit Sub ' source completed 
     Case 4 ' processing text within quotes 
      lngPos = InStr(strSrc, "'") 
      If lngPos = 0 Then Exit Sub ' source completed 
      If Mid(strSrc, lngPos, 2) = "''" Then ' escaped quote char '' 
       strBeg = Left(strSrc, lngPos + 1) ' store preceding chunk with escaped quote char 
       lngPos = lngPos + 2 ' shift next from escaped quote char 
      Else 
       lngMode = 0 ' start normal 
       strBeg = Left(strSrc, lngPos) ' store preceding chunk with quote char 
       lngPos = lngPos + 1 ' shift next from quote char 
      End If 
    End Select 
    Parse Mid(strSrc, lngPos), strRet, lngMode ' recursive parser call 
    strRes = strBeg & strRet ' concatenate preceding chunk with processed and return result 

End Sub 
+0

Danke dafür. Funktioniert gut, außer wenn die Kommentare nicht die ersten Zeichen in der Zeile sind. Gibt es eine einfache Änderung, um dieser Situation Rechnung zu tragen? – John

+0

@John den Code überprüfen, ich habe das Muster behoben. – omegastripes

+0

Nochmals vielen Dank für Ihre Hilfe @omegastripes. Funktioniert perfekt in den meisten Fällen habe ich jetzt versucht. Es gibt eine Ausnahme, die .../ * Das ist ein Kommentar --- annoyingly, so ist dies ‚auch dieses */ – John