Bianca
Bianca

Reputation: 973

Delphi - parsing memo after certain String

I have a memo lines like this:

Mahogany
        Unpolished
        In Stock :  Yes
        Total Stock : 102
Redwood
        Polished
        In Stock :  Yes
        Total Stock : 80
Pine
        Polished
        In Stock :  Yes
        Total Stock : 22

And i want to have only the line of Redwood's Total Stock. Since there are many same string of

Total Stock

I can not use this string as my keyword. So, i use "Redwood" , but i don't know how to get the line of "Total Stock" after "Redwood".

var
  i: Integer;
  s: string;
begin
  for i := 0 to mem0.lines.Count - 1 do
  begin
    if (AnsiContainsStr(mem0.lines[i], 'Redwood')) then
    begin
      // s:= Redwood's total stock, how to do this ?
    end
  end;
end;

Upvotes: 1

Views: 1122

Answers (3)

Rudy Velthuis
Rudy Velthuis

Reputation: 28826

Instead of AnsiContainsStr, you can use StartsWith, since the rest of the lines of the Redwood part are indentend.

var
  I: Integer;
  TotalStockLine: string;
  MyArray: TArray<string>
begin
  for I := 0 to Memo1.Lines.Count - 1 do
    if Memo.Lines[I].StartsWith('Redwood') then
    begin
      TotalStockLine := Trim(Memo.Lines[I + 3];
      Break;
    end;
  if TotalStockLine <> '' then
  begin
    MyArray := TotalStockLine.Split([':']);
    TotalStock := StrToInt(Trim(MyArray[1]));
  end;

etc... This can probably be simplified a little, but that shows how you could do this.

FWIW, this assumes you are using XE3 or later. Otherwise you must use the standalone StartsWith.

Upvotes: 2

MartynA
MartynA

Reputation: 30725

You could try this, but like your original code it's a bit 'fragile' in that it makes assumptions about the layout of the text you're searching (in particular that the text you're searching through is packaged in a TStrings object):

function TotalForItem(const ItemName : String; Strings : TStrings) : String;
 var
  i,
  j,
  p : Integer;
  s : string;
  TotalLineIntro : String;
begin
  Result := '';
  TotalLineIntro := 'Total Stock : ';
  for i := 0 to Strings.Count - 1 do
  begin
    if (Pos(ItemName, Strings[i]) > 0) then
    begin
      for j:= i + 1 to Strings.Count - 1 do begin
        p := Pos(TotalLineIntro, Strings[j]);
        if p > 0 then
        begin
          Result := Copy(Strings[j], p + Length(TotalLineIntro), Length(Strings[j]));
          exit;
        end;
      end;
    end
  end;
end;

procedure TForm3.Button1Click(Sender: TObject);
begin
  ShowMessage(TotalForItem('Redwood', Memo1.Lines));
end;

Upvotes: 3

David Heffernan
David Heffernan

Reputation: 613163

The missing code is:

s := mem0.Lines[i+3];

This makes the assumption that the format of the data is always exactly as seen in the question. If that assumption is valid then this simple code is the best solution.


It would probably make more sense to use one of the standard human readable structured data formats like JSON or YAML that have good parsers and emitters. Sadly the support for YAML on Delphi is essentially non-existant so that leaves JSON.

Upvotes: 3

Related Questions