procedure SplitLine(Line: String; List: TStrings; AllowSpaceAroundEqualSign: Boolean = True);
type
TState = (stInBetween, stKeyStart, stInKey, stAfterKey, stEqualSign, stAfterEqualSign, stQuoteStart, stInValue, stQuoteEnd);
var
State: TState;
i, Len, KeyStart, ValueStart: Integer;
Ch: Char;
Key, Value: String;
begin
List.Clear;
KeyStart := MaxInt;
ValueStart := MaxInt;
i := 1;
Len := Length(Line);
if (Len = 0) then
Exit;
State := stInBetween;
i := 1;
for i := 1 to Len do
begin
if not AllowSpaceAroundEqualSign and (State in [stAfterKey, stAfterEqualSign]) then
Exit;
Ch := Line[i];
//write('i=',i:2,' State=',State:18,' Ch=>',Ch,'<');
case Ch of
#32:
begin
case State of
stInBetween, stAfterKey, stAfterEqualSign, stInValue: ;
stKeyStart, stInKey:
begin
State := stAfterKey;
Key := Copy(Line, KeyStart, i-KeyStart);
end;
stEqualSign: State := stAfterEqualSign;
stQuoteStart: State := stInValue;
stQuoteEnd: State := stInBetween;
end// case State
end;
'=':
begin
case State of
stInBetween: Exit; // did not find a Key yet
stKeyStart, stInKey:
begin // end of Key
State := stEqualSign;
Key := Copy(Line, KeyStart, i-KeyStart);
end;
stAfterKey: State := stEqualSign; //KeyEnd should be marked elsewhere already
stAfterEqualSign,stEqualSign: Exit; //cannot have sonsecutive equal signs, even with space between them
stQuoteStart:
begin //first char of Value
State := stInValue;
ValueStart := i;
end;
stInValue: ; //part of Value
stQuoteEnd: Exit; //char directly after closing " can only be space
end// case State
end;
'"':
begin
case State of
stInBetween: Exit; // only start of a Key allowed here
stKeyStart, stInKey, stAfterKey: Exit; // did not find equal sign yet
stEqualSign: State := stQuoteStart; //Start of Value
stAfterEqualSign: State := stQuoteStart; //Start of Value
stQuoteStart, stInValue:
begin //end of Value
if (Key = '') or (ValueStart = MaxInt) then //sanity check
begin
//writeln;
//writeln('SplitLine Error');
//writeln('Key=[',Key,'], ValueStart=',ValueStart);
Exit; //at this point Key should never be empty and ValueStart should have been set.
end;
State := stQuoteEnd;
Value := Copy(Line, ValueStart, i-ValueStart);
List.AddPair(Key, Value);
Key := '';
Value := '';
KeyStart := MaxInt;
ValueStart := MaxInt;
end;
stQuoteEnd: Exit; //cannot have 2 consecutive quotes
end// case State
end;
otherwise
begin //"normal" character
case State of
stInBetween:
begin
State := stKeyStart;
KeyStart := i;
end;
stKeyStart: State := stInKey;
stInKey, stInValue: ;
stAfterKey: Exit; //only space or = is valid after a Key
stEqualSign, stAfterEqualSign: Exit; //only space or " is valid after equal sign
stQuoteStart:
begin
State := stInValue;
ValueStart := i;
end;
stQuoteEnd: Exit; //there can only be space after closing "
end// case State
end;
end;//case Ch
//writeln(' State->',State);
end;//for
end;