RegEx war für mich immer ein Buch mit sieben Siegeln. Da schreibe ich mir lieber meinen eigenen Scanner. Der folgende Code nimmt an, dass
- eine SQL-Anweisung über mehrere Zeilen gehen kann und mit einem Strichpunkt endet.
- ein Kommentar mit '/*' und '*/* umschlossen ist, und
- ein einzeiliger Kommentar mit '--' eingeleitet wird.
Damit extrahiert die folgende Routine jede SQL-Anweisung und schreibt sie als einzelne Zeile in eine StringList:
Code: Alles auswählen
const
LE = LineEnding; // oder: #13 oder #10
SQL =
'-- --------------------------------------------------------' + LE +
'-- Host: 127.0.0.1' + LE +
'-- Server Version: 10.1.13-MariaDB - mariadb.org binary distribution'+ LE +
'-- --------------------------------------------------------' + LE +
'' + LE +
'/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */' + LE +
'/*!40101 SET NAMES utf8mb4 */' + LE +
'' + LE +
'-- Exportiere Datenbank Struktur für tanzdb' + LE +
'CREATE DATABASE IF NOT EXISTS `einedb` /*!40100 DEFAULT CHARACTER SET utf8 */;' + LE +
'USE `einedb`;' + LE +
'' + LE +
'/* Mehrzeiliger Kommentar' + LE +
' und auch Statements über mehrere zeilen*/' + LE +
'CREATE TABLE IF NOT EXISTS `kunden` (' + LE +
' `KDID` int(11) NOT NULL AUTO_INCREMENT,' + LE +
' `Geschlecht` varchar(255) NOT NULL DEFAULT '',' + LE +
' PRIMARY KEY (`KDID`),' + LE +
' UNIQUE KEY `KDID` (`KDID`),' + LE +
' KEY `Nachname` (`Nachname`)' + LE +
') ENGINE=MyISAM DEFAULT CHARSET=utf8;';
procedure ExtractSQL(SQL: String; Cmds: TStrings);
var
P, Q: PChar;
PEnd: PChar;
s: String;
n: Integer;
begin
SetLength(s, Length(SQL));
n := 0;
P := @SQL[1];
PEnd := P + Length(SQL);
while (P < PEnd) do begin
Q := P+1;
if (P^ = '-') and (Q^ = '-') then begin
// Einzeiliger Kommentar: bis zum Ende der Zeile ignorieren
while (P < PEnd) do begin
if (P^ = #13) and (Q^ = #10) then begin
inc(P);
break;
end
else
if (P^ = #13) or (P^ = #10) then
break;
inc(P);
inc(Q);
end;
end else
if (P^ = '/') and (Q^ = '*') then begin
// "normaler" Kommentar
while (P < PEnd) do begin
if (P^ = '*') and (Q^ = '/') then begin
inc(P);
break;
end;
inc(P);
inc(Q);
end;
end else
if (P^ = #13) and (Q^ = #10) then begin
// Zeilenumbruch #13#10
inc(P);
inc(Q, 2);
if n > 0 then begin
inc(n);
s[n] := ' ';
end;
// Einrückung überlesen
while (Q < PEnd) and (Q^ = ' ') do begin
inc(P);
inc(Q);
end;
end else
if (P^ = #13) or (P^ = #10) then begin
// Zeilenumbruch #13 oder #10
inc(Q);
if n > 0 then begin
inc(n);
s[n] := ' ';
end;
// Einrückung überlesen
while (Q < PEnd) and (Q^ = ' ') do begin
inc(P);
inc(Q);
end;
end else
if P^ = ';' then begin
// Ende der Anweisung
inc(n);
s[n] := ';';
SetLength(s, n);
Cmds.Add(s);
SetLength(s, Length(SQL));
n := 0;
end else begin
// Zeichen der Anweisung sammeln
inc(n);
s[n] := P^;
end;
inc(P);
end;
if n > 0 then begin
SetLength(s, n);
Cmds.Add(s);
end;
end;
{ TForm1 }
procedure TForm1.FormCreate(Sender: TObject);
begin
Memo1.Lines.Text := SQL;
ExtractSQL(SQL, Memo2.Lines);
end;