The following routine is one I wrote (more accurately, adapted from SetDelimitedText
and ExtractStrings
) for Delphi 7 to handle the lack of the TStrings.StrictDelimiter
property. Given the correct parameters, it'll return exactly the results you want.
{
SplitString will expand the delimited string S into its component parts and
store them in Strings. The primary difference between this routine and
Classes.ExtractStrings and TStrings.DelimitedText is that it does not treat
spaces, tabs, and CR/LF as delimiters whether you like it or not. If Quotes
is non-empty, then quoted strings will be handled correctly.
Leading and Trailing whitespace is significant if TrimStrings is False.
If you want to eliminate empty tokens, set SkipEmptyStrings to True.
If you want Strings to be cleared before parsing, set ClearStrings to True.
This procedure is especially useful for dealing with CSV files exported from
Excel, since Excel does not quote a string unless it contains a comma.
Using ExtractStrings or TStrings.CommaText will fail with such files.
In Delphi 2006+, TStrings has the StrictDelimiter property that renders this
routine largely useless.
}
procedure SplitString(const S: string; Separators, Quotes: TSysCharSet; const Strings: TStrings; ClearStrings, TrimStrings, SkipEmptyStrings: Boolean);
var
Head, Tail: PChar;
Item: string;
StringExists: Boolean;
{$IF NOT Declared(CharInSet)}
function CharInSet(C: Char; const CharSet: TSysCharSet): Boolean;
begin
Result := C in CharSet;
end;
{$IFEND}
begin
StringExists := False;
Strings.BeginUpdate;
try
if ClearStrings then
Strings.Clear;
if S = '' then
Exit;
Tail := PChar(S);
while Tail^ <> #0 do begin
if CharInSet(Tail^, Quotes) then
Item := AnsiExtractQuotedStr(Tail, Tail^)
else begin
// Mark beginning of token
Head := Tail;
// Look for end of token, delineated by end of string or separator
while (Tail^ <> #0) and not CharInSet(Tail^, Separators) do
Inc(Tail);
SetString(Item, Head, Tail - Head);
if TrimStrings then begin
Item := Trim(Item);
Head := PChar(Item);
if CharInSet(Head^, Quotes) then
Item := Trim(AnsiExtractQuotedStr(Head, Head^));
end;
if not (SkipEmptyStrings and (Item = '')) then
Strings.Append(Item);
end;
// If the last character in a string is a separator, then we need to mark
// that another string exists, otherwise the next Inc(Tail) call will
// place Tail^ at #0, we'll exit the while loop, and never know that there
// was an empty string there to add.
// --AAF
StringExists := Tail^ <> #0;
// Skip Separator
if StringExists then
Inc(Tail);
end;
// This can only happen if the very last character is a separator
if StringExists and not SkipEmptyStrings then
Strings.Append('');
finally
Strings.EndUpdate;
end;
end;