program CsvReader;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.Classes,
System.SysUtils;
type
TEndOfLineOption = (eolCR, eolLF, eolCRLF);
TCsvReader =
class
private
FReader: TStreamReader;
FQuoteChar: Char;
FDelimiter: Char;
FEndOfLine: TEndOfLineOption;
procedure Initialize();
function GetEndOfStream: Boolean;
public
constructor Create(Stream: TStream);
overload;
constructor Create(Stream: TStream; DetectBOM: Boolean);
overload;
constructor Create(Stream: TStream; Encoding: TEncoding; DetectBOM: Boolean = False; BufferSize: Integer = 4096);
overload;
constructor Create(
const Filename:
string);
overload;
constructor Create(
const Filename:
string; DetectBOM: Boolean);
overload;
constructor Create(
const Filename:
string; Encoding: TEncoding; DetectBOM: Boolean = False; BufferSize: Integer = 4096);
overload;
destructor Destroy;
override;
property Delimiter: Char
read FDelimiter
write FDelimiter;
property EndOfLine: TEndOfLineOption
read FEndOfLine
write FEndOfLine;
property EndOfStream: Boolean
read GetEndOfStream;
property QuoteChar: Char
read FQuoteChar
write FQuoteChar;
procedure OwnStream();
function ReadLine(): TArray<
string>;
end;
{ TCsvReader }
constructor TCsvReader.Create(Stream: TStream; Encoding: TEncoding; DetectBOM: Boolean; BufferSize: Integer);
begin
inherited Create();
Initialize();
FReader := TStreamReader.Create(Stream, Encoding, DetectBOM, BufferSize);
end;
constructor TCsvReader.Create(Stream: TStream; DetectBOM: Boolean);
begin
inherited Create();
Initialize();
FReader := TStreamReader.Create(Stream, DetectBOM);
end;
constructor TCsvReader.Create(Stream: TStream);
begin
inherited Create();
Initialize();
FReader := TStreamReader.Create(Stream);
end;
constructor TCsvReader.Create(
const Filename:
string; Encoding: TEncoding; DetectBOM: Boolean; BufferSize: Integer);
begin
inherited Create();
Initialize();
FReader := TStreamReader.Create(Filename, Encoding, DetectBOM, BufferSize);
end;
constructor TCsvReader.Create(
const Filename:
string; DetectBOM: Boolean);
begin
inherited Create();
Initialize();
FReader := TStreamReader.Create(Filename, DetectBOM);
end;
constructor TCsvReader.Create(
const Filename:
string);
begin
inherited Create();
Initialize();
FReader := TStreamReader.Create(Filename);
end;
destructor TCsvReader.Destroy;
begin
FReader.Free();
inherited;
end;
function TCsvReader.GetEndOfStream: Boolean;
begin
Result := FReader.EndOfStream;
end;
procedure TCsvReader.Initialize;
begin
FDelimiter := '
,';
FQuoteChar := '
"';
FEndOfLine := eolCRLF;
end;
procedure TCsvReader.OwnStream;
begin
FReader.OwnStream();
end;
function TCsvReader.ReadLine: TArray<
string>;
var
str:
string;
c: Char;
LineDelimiter:
string;
sl: TStringList;
QuoteCountEven: Boolean;
EndsWithLineDelimiter: Boolean;
begin
case EndOfLine
of
eolCR:
LineDelimiter := #13;
eolLF:
LineDelimiter := #10;
eolCRLF:
LineDelimiter := #13#10;
else
raise Exception.Create('
Fehlermeldung');
end;
if FReader.EndOfStream
then
raise EInvalidOpException.Create('
End of stream');
str :=
string.Empty;
repeat
c := Char(FReader.
Read());
str := str + c;
QuoteCountEven := str.CountChar(QuoteChar)
mod 2 = 0;
EndsWithLineDelimiter := str.EndsWith(LineDelimiter);
until FReader.EndOfStream
or (EndsWithLineDelimiter
and QuoteCountEven);
if not QuoteCountEven
then
raise EInvalidOpException.Create('
Quote parse error');
if EndsWithLineDelimiter
then
str := str.Substring(0, str.Length - LineDelimiter.Length);
sl := TStringList.Create();
try
sl.Delimiter := Delimiter;
sl.StrictDelimiter := True;
sl.DelimitedText := str;
Result := sl.ToStringArray();
finally
sl.Free();
end;
end;
procedure Main();
const
sample = '
' +
//
'
a,b,c' + sLineBreak +
//
'
a,"b",c' + sLineBreak +
//
'
a,"b1,b2",c' + sLineBreak +
//
'
a,"b1' + sLineBreak + '
b2",c';
var
s: TStringStream;
r: TCsvReader;
l: TArray<
string>;
begin
s := TStringStream.Create(sample);
try
r := TCsvReader.Create(s);
try
r.Delimiter := '
,';
r.QuoteChar := '
"';
r.EndOfLine := eolCRLF;
while not r.EndOfStream
do
begin
l := r.ReadLine();
WriteLn(
string.Join('
| ', l));
end;
finally
r.Free();
end;
finally
s.Free();
end;
end;
begin
try
Main();
except
on E:
Exception do
WriteLn(E.ClassName, '
: ', E.
Message);
end;
Readln;
end.