Hi,
Trying not to re-invent the wheel here.
I have a string as input;
It consists of multiple Key-Value pairs.
They are in the form:
Key="Value" (so, values are quoted, keys aren't)
There will never be a double quote inside a Value.
The order in which the Key-Value pairs appear in the string may vary with time.
I want to extract the Key-Value pairs into some type of record.
I've done so using multiple Pos() and Copy() calls.
The problem here may be that you can have Pairs like:
TYPE="Foo"
NEWTYPE="Bar"
And then Pos('TYPE=', AString) will find either of the above two, depending on order or startpos (last param in Pos()).
My goal here is to not be dependant on the order in which the Key-Value pairs appear in the string.
Notice: speed is not important here.
I'm parsing strings derived from executing other programs, which takes orders of magnitude more time than string parsing.
Since TStrings already has a mecahnism to read Values from Keys, I want to use that, since it's been tested and reliable.
So:
How do I parse the input string into in TStrings?
I've come up with this for now:
procedure SplitLine(Line: String; List: TStrings);
var
Len, i, PStart: Integer;
Pair, Key, Value: String;
begin
List.Clear;
i := 1;
Len := Length(Line);
if (Len = 0) then
Exit;
Pair := '';
while (i <= Len) do
begin
while (i < Len) and (Line[i] = #32) do Inc(i); //skip whitespace
PStart := i; //first non-white space: must be start of Key
if (Line[i] in ['"','=']) then //Key cannot start with those
Exit;
while (i < Len) and not (Line[i] in ['=','"']) do Inc(i); //find equal sign, we cannot find a quote before the equal sign as it cannot be part of e Key
if (Line[i] <> '=') then
Exit;
Inc(i);
if (i > Len) or (Line[i] <> '"') then //next char must be a doublequote
Exit;
Key := TrimRight(Copy(Line, PStart, i-PStart)); //don't copy the starting doublequote, allow for trailing spaces
//writeln('Key=',Key);
Inc(i);
PStart := i;
while (i < Len) and (Line[i] <> '"') do Inc(i); //find closing doublequote (there cannot be quotes inside Value, they will be escaped like \x<hexvalue>
if (i > Len) or (Line[i] <> '"') then //no closing double quote -> error
Exit;
Value := Copy(Line, PStart, i-PStart); //don't copy the closing doublequote
writeln('Value=',Value);
Pair := Key + Value;
//writeln('Pair=[',Pair,']');
List.Add(Pair);
Inc(i);
end;
end;
It does some limited checking of false input.
In the end it would not really matter if some invalid Key-Value pair ends up in then TStrings, as long as all good pairs are included.
Questions:
Am I re-inventing the wheel here (converting the string to TStrings)?
Any better solutions?
Mind you: I prefer verbose code over cryptic but faster code, and I prefer strings over pchar's..
Bart