-2

I'm trying to compare 2 stringlist by substring search, and match the found items into another stringlist.

"Stringlist_SCSILogicalUnit" contains data like:

SCSIBus=0;SCSILogicalUnit=0;SCSIPort=1;SCSITargetId=0;Status=OK
SCSIBus=0;SCSILogicalUnit=1;SCSIPort=2;SCSITargetId=0;Status=OK
SCSIBus=0;SCSILogicalUnit=2;SCSIPort=2;SCSITargetId=0;Status=OK
SCSIBus=0;SCSILogicalUnit=3;SCSIPort=2;SCSITargetId=0;Status=OK
SCSIBus=0;SCSILogicalUnit=4;SCSIPort=2;SCSITargetId=0;Status=OK
SCSIBus=0;SCSILogicalUnit=43;SCSIPort=2;SCSITargetId=0;Status=OK
SCSIBus=0;SCSILogicalUnit=44;SCSIPort=2;SCSITargetId=0;Status=OK
SCSIBus=0;SCSILogicalUnit=45;SCSIPort=2;SCSITargetId=0;Status=OK
SCSIBus=0;SCSILogicalUnit=46;SCSIPort=2;SCSITargetId=0;Status=OK

"Stringlist_LUN" contains data like:

  LocationInformation    REG_SZ    Port(2,2,3,3) Bus 0, Target ID 0, LUN 67
;
    LocationInformation    REG_SZ    Port(2,2,3,3) Bus 0, Target ID 0, LUN 43
;
    LocationInformation    REG_SZ    Port(2,2,3,3) Bus 0, Target ID 0, LUN 44
;
    LocationInformation    REG_SZ    Port(2,2,3,3) Bus 0, Target ID 0, LUN 45
;
    LocationInformation    REG_SZ    Port(2,2,3,3) Bus 0, Target ID 0, LUN 50
;
    LocationInformation    REG_SZ    Port(2,2,3,3) Bus 0, Target ID 0, LUN 51
;

I need to match the corespondence between "LUN" value and "SCSILogicalUnit" value (LUN and SCSILogicalUnit have the same value Lun=SCSILogicalUnit)so that the result can be listen in "Stringlist_result". The result shoud look like

"SCSIBus=0;SCSILogicalUnit=46;SCSIPort=2;SCSITargetId=0;Status=OK =>>> LocationInformation    REG_SZ    Port(2,2,3,3) Bus 0, Target ID 0, LUN 46
;"

I'm using the following function but the result is not consistent:

function stringlist_mmg_FastJoin(List1, List2: TStringList): TStringList;
var
  L1Idx, L2Idx,
  L1Max, L2Max: Integer;
  v: Integer;
begin
  // Create Result list, set it's min size
  Result := TStringList.Create;
  Result.Capacity := Max(List1.Count, List2.Count);
  // limits
  L1Idx := 0;
  L2Idx := 0;
  L1Max := List1.Count;
  L2Max := List2.Count;
  // forse sort
  List1.Sorted := True;
  List2.Sorted := True;

  // iterate
  while (L1Idx<L1Max) and (L2Idx<L2Max) do
  begin

if pos(extracttextbetween(List1[L1idx],'SCSILogicalUnit=',';'),List2[L2idx])>1  then


    begin
      Result.Add(List1[L1Idx]+' = '+List2[L2idx]);
      Inc(L1Idx);
      Inc(L2Idx);
    end

    else if v < 0 then                              // Add from List 1
    begin
      //Result.Add(List1[L1Idx]);
      Inc(L1Idx);
    end
    else // v > 0                                   // Add from List 2
    begin
      //Result.Add(List2[L2Idx]);
      Inc(L2Idx);
    end;
  end;
  // Add all remainders from second list
  while L2Idx < L2Max do
  begin
    //Result.Add(List2[L2Idx]);
    Inc(L2Idx);

  end;
  end;



stringlist_resultat:=Tstringlist.create;
stringlist_rezultat.addstrings(stringlist_mmg_FastJoin(Stringlist_SCSILogicalUnit,stringlist_LUN));

The result shoud be:

PNPDeviceID=MPIOSCSIBus=0;SCSILogicalUnit=67;SCSIPort=2;SCSITargetId=0;Status=OK =>>>     LocationInformation    REG_SZ    Port(2,2,3,3) Bus 0, Target ID 0, LUN 67
;

When I run the function I get a sigle result.

Could someone please tell what am I doing wrong? Can this task be obtimized without a stringlist?

Thank you!

user2858981
  • 235
  • 4
  • 23
  • 1
    You should be using dictionaries for this problem. Parse the two files into dictionaries keyed on the Lum value. – David Heffernan Jun 23 '18 at 08:05
  • Could you provide an exemple? – user2858981 Jun 23 '18 at 08:26
  • 1
    Not really motivated to do that. There are lots of examples around for the various parts. – David Heffernan Jun 23 '18 at 08:27
  • 2
    Also Delphi 2010 is ancient and it's generic collections are a bit flaky. Although they probably work well enough for this simple task. If I were you I'd parse with regex and dictionaries should do the rest. Once you have the right tools in place the code largely writes itself and you'll be able to throw away lots of what you have here. – David Heffernan Jun 23 '18 at 08:40
  • 50 rep probably not enough to get anybody motivated. That's just one good answer to a decent question. Far more interesting for us to do that. – David Heffernan Jun 25 '18 at 16:09

1 Answers1

1

Renamed that to just Join, can't claim its fast..

function stringlist_mmg_Join(const LogicalUnitList, LUNList: TStringList): TStringList;
const NotFound = -1;

  function ExtractTextBetween(const Txt, StartTag, EndTag : string; out iValue : integer): Boolean;
  var
    value : string;
    iStartTag, iEndTag : integer;
  begin
    Result := False;

    iStartTag := Pos(StartTag, Txt);
    if (iStartTag = NotFound) then Exit;

    iEndTag := PosEx(EndTag, Txt, iStartTag);
    if (iEndTag = NotFound) then Exit;

    Inc(iStartTag, Length(StartTag));
    Value := MidStr(Txt, iStartTag, iEndTag-iStartTag);
    Result := TryStrToInt(Value, iValue);
  end;

var
  i, v, ix: Integer;
begin
  Result := TStringList.Create;

  // iterate, Parse and write Value as Object
  for i := 0 to LogicalUnitList.Count - 1 do begin
     If ExtractTextBetween(LogicalUnitList[i], 'SCSILogicalUnit=', ';', v) then begin
       LogicalUnitList.Objects[i] := Pointer(V+1);
     end;
  end;

  // iterate, Parse and write Value as Object
  for i := 0 to LUNList.Count - 1 do begin
     If ExtractTextBetween(LUNList[i] + ';', 'LUN ', ';', v) then begin
       LUNList.Objects[i] := Pointer(V+1);
     end;
  end;

  // Match
  for i := 0 to LogicalUnitList.Count - 1 do begin
    ix := LUNList.IndexOfObject(LogicalUnitList.Objects[i]);
    if (ix = NotFound) then Continue;
    Result.Add(LogicalUnitList[i] + '  =>>>' + LUNList[ix] + ';');
  end;
end;

Ouput is:

SCSIBus=0;SCSILogicalUnit=43;SCSIPort=2;SCSITargetId=0;Status=OK  =>>>    LocationInformation    REG_SZ    Port(2,2,3,3) Bus 0, Target ID 0, LUN 43;
SCSIBus=0;SCSILogicalUnit=44;SCSIPort=2;SCSITargetId=0;Status=OK  =>>>    LocationInformation    REG_SZ    Port(2,2,3,3) Bus 0, Target ID 0, LUN 44;
SCSIBus=0;SCSILogicalUnit=45;SCSIPort=2;SCSITargetId=0;Status=OK  =>>>    LocationInformation    REG_SZ    Port(2,2,3,3) Bus 0, Target ID 0, LUN 45;
FredS
  • 630
  • 1
  • 5
  • 6
  • The result of this functions is wrong: SCSIBus=0;SCSILogicalUnit=0;SCSIPort=2;SCSITargetId=0;Status=OK =>>> Port(2,2,3,3) Bus 0, Target ID 0, LUN 67 It matches SCSILogicalUnit=0 to LUN 67 ;; – user2858981 Jun 26 '18 at 04:26
  • Thank you FredS! This works perfectly. You deserve the bounty! – user2858981 Jun 26 '18 at 07:39