Recent

Author Topic: Strings Again  (Read 6412 times)

garlar27

  • Hero Member
  • *****
  • Posts: 652
Re: Strings Again
« Reply #15 on: December 07, 2018, 10:39:46 pm »
Did anybody suggest using TStringList.CommaText?
Didn't know about it  :o

jamie

  • Hero Member
  • *****
  • Posts: 6130
Re: Strings Again
« Reply #16 on: December 07, 2018, 11:45:22 pm »
He needs a parsing "GET" function, one that ignores spaces as it builds a captured string until a comma is hit and
thus remembers where it was the last time for the next read of the string.

For example

Var
 X:Integer;
 S:Sting;
Begin
 X ;= 0; first initial setting for the line.

 S:= GET(X);
 While S <> '' Do begin
  begin
    // do something with S;
   S := GET(X); // the Get function will auto increment for the next location.
 End;


The GET function may also consider accepting spaces for the content if there was a quote started.

I am sure with all the powers to be here, someone can hack out a function like that..  :)

 
The only true wisdom is knowing you know nothing

JLWest

  • Hero Member
  • *****
  • Posts: 1293
Re: Strings Again
« Reply #17 on: December 08, 2018, 12:15:25 am »
Have been trying to make the function supplied by Handoko but it only eturns the first field.

It close but I can't figure out why it won't return the second or fourth field.

Attached is a self contained demo using the function.

Code: Pascal  [Select][+][-]
  1.      function TForm1.GetFieldNo(const aText: String; aFieldNo: Integer; out fieldCount: Integer): String;
  2.     const
  3.       Comma = ',';
  4.     type
  5.       TPosArray = array[1..9] of Integer;
  6.     var
  7.       txt: String;
  8.       arr:  TPosArray;
  9.       i: Integer;
  10.     begin
  11.       fieldCount := 0;
  12.       txt := Trim(aText);
  13.       arr := Default(TPosArray);
  14.       if (Length(txt) < 2) or (Pos(Comma, txt) = 0) or (aFieldNo < 1) then
  15.         Exit('');
  16.       for i := 1 to Length(txt) do
  17.         if txt[i] = Comma then
  18.           begin
  19.             Inc(fieldCount);
  20.             arr[fieldCount] := i;
  21.           end;
  22.       if aFieldNo > Succ(fieldCount) then
  23.         Exit('');
  24.       case aFieldNo = 1 of
  25.         True:  Result := Trim(Copy(txt, 1, Pred(arr[1])));
  26.         False: begin
  27.                  if aFieldNo = Succ(fieldCount) then
  28.                    Result := Trim(Copy(text, Succ(arr[fieldCount]), Length(text)))
  29.                  else Result := Trim(Copy(text, Succ(arr[Pred(aFieldNo)]), Pred(arr[aFieldNo] - arr[Pred(aFieldNo)])));
  30.                end;
  31.       end;
  32.       Inc(fieldCount);
  33.     end;                        

 
FPC 3.2.0, Lazarus IDE v2.0.4
 Windows 10 Pro 32-GB
 Intel i7 770K CPU 4.2GHz 32702MB Ram
GeForce GTX 1080 Graphics - 8 Gig
4.1 TB

wp

  • Hero Member
  • *****
  • Posts: 11916
Re: Strings Again
« Reply #18 on: December 08, 2018, 12:37:58 am »
JLWest, did you consider Bart's suggestion with TStringList in reply #14? It works perfectly:
Code: Pascal  [Select][+][-]
  1. program Project1;
  2.  
  3. uses
  4.   Classes;
  5.  
  6. const
  7.   s =  'LAN  ,   YSSY  ,   NZAA  ,   B789_LAN_LATAM  ,  0010  ,   LA800  ,   CC-BGA  ,  0  ,0325';
  8.  
  9. var
  10.   i: Integer;
  11.   L: TStringList;
  12. begin
  13.   L := TStringList.Create;
  14.   try
  15.     L.CommaText := s;
  16.     WriteLn(L.count, ' items:');
  17.     for i:=0 to L.Count-1 do
  18.       WriteLn('"', L[i], '"');
  19.   finally
  20.     L.Free;
  21.   end;
  22.  
  23.   ReadLn;
  24. end.

Output (the quotes were added to show whether the spaces are trimmed correctly):
Quote
9 items:
"LAN"
"YSSY"
"NZAA"
"B789_LAN_LATAM"
"0010"
"LA800"
"CC-BGA"
"0"
"0325"

jamie

  • Hero Member
  • *****
  • Posts: 6130
Re: Strings Again
« Reply #19 on: December 08, 2018, 12:46:52 am »
as WP pointed out, that will work fine but since I've already banged out some code I just have to post it here  :)
Code: Pascal  [Select][+][-]
  1. { TForm1 }
  2. Function GET(Const InputStr:String;Var X :Integer):String;
  3. begin
  4.   Result := '';
  5.   Repeat
  6.    Inc(X); // move to next char;
  7.    If X > Length(Inputstr) Then
  8.     Begin
  9.      Dec(X);
  10.      Exit;// done;
  11.     End;
  12.    If Not (InputStr[X] in[' ',',']) Then Result := Result+inputstr[x];
  13.   Until InputStr[X] = ',';
  14. end;
  15.  
  16. procedure TForm1.Button1Click(Sender: TObject);  //Test run..
  17. Var
  18.   A:Array[1..20] of string;
  19.   X,Aindex:Integer;
  20.   S,B:String;
  21. begin
  22.    X := 0; Aindex := 0;
  23.    S:= 'Some_Test_String , To_See_if_it_Works  ,END'; //Fake string for test.
  24.    B := Get(S,X);  //Get the first one;
  25.    While B <> '' do
  26.     Begin
  27.       Inc(AIndex);    //Number of entries of string;
  28.       A[AIndex] := B;  //Store each one in a string by itself;
  29.       Caption := Caption+B; //Use CAPTION as a repository and debug display.
  30.       B := Get(S,X);  //Get next;
  31.     end;
  32. // at this point the aIndex should be 1 or more, if 0 then nothing in string;
  33. // Also after each read, X will be resting at a ',' or length of input string, which means no more.
  34. end;                                                                                  
  35.  
The only true wisdom is knowing you know nothing

lucamar

  • Hero Member
  • *****
  • Posts: 4219
Re: Strings Again
« Reply #20 on: December 08, 2018, 01:03:04 am »
This one should work too, but I didn't test it :-[

Code: Pascal  [Select][+][-]
  1. function CutLoc(aInt: Integer; const aStr: string): Integer;
  2. var
  3.   Loc, Count: Integer;
  4. begin
  5.   Count := 0;
  6.   Loc := 1;
  7.   repeat
  8.     { Find the next "," from position Loc }
  9.     Loc := PosEx(',', aStr, Loc);
  10.     { Found one? update the count of commas
  11.       and the next starting position}
  12.     if Loc > 0 then begin
  13.       Inc(Count);
  14.       Inc(Loc);
  15.     end;
  16.   until (Count = aInt) or (not (Loc in [1..Length(aStr)]));
  17.   if Count <> aInt then
  18.     { Not enough commas! Do something }
  19.   else
  20.     Result := Loc;
  21. end;
  22.  
« Last Edit: December 08, 2018, 01:51:53 am by lucamar »
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus/FPC 2.0.8/3.0.4 & 2.0.12/3.2.0 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

JLWest

  • Hero Member
  • *****
  • Posts: 1293
Re: Strings Again
« Reply #21 on: December 08, 2018, 08:53:11 am »
JLWest, did you consider Bart's suggestion with TStringList in reply #14? It works perfectly:
Code: Pascal  [Select][+][-]
  1. program Project1;
  2.  
  3. uses
  4.   Classes;
  5.  
  6. const
  7.   s =  'LAN  ,   YSSY  ,   NZAA  ,   B789_LAN_LATAM  ,  0010  ,   LA800  ,   CC-BGA  ,  0  ,0325';
  8.  
  9. var
  10.   i: Integer;
  11.   L: TStringList;
  12. begin
  13.   L := TStringList.Create;
  14.   try
  15.     L.CommaText := s;
  16.     WriteLn(L.count, ' items:');
  17.     for i:=0 to L.Count-1 do
  18.       WriteLn('"', L[i], '"');
  19.   finally
  20.     L.Free;
  21.   end;
  22.  
  23.   ReadLn;
  24. end.

Output (the quotes were added to show whether the spaces are trimmed correctly):
Quote
9 items:
"LAN"
"YSSY"
"NZAA"
"B789_LAN_LATAM"
"0010"
"LA800"
"CC-BGA"
"0"
"0325"

I have tried for a couple of days to get this to work. And I have trouble with each suggestion.
I have got the line parsed for 7 of the 9 fields , but the 8th and 9th fields give me a lot of trouble. A record will always have 8 fields but the 9 field is optional.

Now I'm looking at the TStringList solution.

It looks simple.
Will something like this workl

I read a record from the file: TFRecord

L := TStringList.Create;
 try
    L.CommaText := TFRecord;
for i:=0 to L.Count-1 do Begin <----------------- going thru the list of fields
      Field := L;                 <-------------------- Field is a String             
     ValidField :=  VerifyField(Field); <------------ValidField is a Boolean
end; <----------------------------------------------End of list
  finally
    L.Free;

I'll try this tomorrow.
FPC 3.2.0, Lazarus IDE v2.0.4
 Windows 10 Pro 32-GB
 Intel i7 770K CPU 4.2GHz 32702MB Ram
GeForce GTX 1080 Graphics - 8 Gig
4.1 TB

wp

  • Hero Member
  • *****
  • Posts: 11916
Re: Strings Again
« Reply #22 on: December 08, 2018, 10:04:10 am »
L := TStringList.Create;
 try
    L.CommaText := TFRecord;
for i:=0 to L.Count-1 do Begin <----------------- going thru the list of fields
      Field := L;                 <-------------------- Field is a String             
     ValidField :=  VerifyField(Field); <------------ValidField is a Boolean
end; <----------------------------------------------End of list
  finally
    L.Free;
This actually is correct although the line "Field := L" looks wrong. This is because the forum software swallows the character i enclosed by square brackets. I am repeating your code here using the index j instead of i to demonstrate that it does not contain a line "Field := L"

L := TStringList.Create;
 try
    L.CommaText := TFRecord;
for j:=0 to L.Count-1 do Begin <----------------- going thru the list of fields
      Field := L[j];                 <-------------------- Field is a String             
     ValidField :=  VerifyField(Field); <------------ValidField is a Boolean
end; <----------------------------------------------End of list
  finally
    L.Free;
end;

In general it would be better to enclose your source code by [code ] tags (Select it and click on the # button above the edit field):
Code: Pascal  [Select][+][-]
  1. L := TStringList.Create;
  2.  try
  3.     L.CommaText := TFRecord;
  4. for i:=0 to L.Count-1 do Begin <----------------- going thru the list of fields
  5.       Field := L[i];                 <-------------------- Field is a String            
  6.      ValidField :=  VerifyField(Field); <------------ValidField is a Boolean
  7. end; <----------------------------------------------End of list
  8.   finally
  9.     L.Free;
  10.   end;
  11.  

JLWest

  • Hero Member
  • *****
  • Posts: 1293
Re: Strings Again
« Reply #23 on: December 08, 2018, 06:26:18 pm »
Yea, I noticed I could't get the '[' ']' to display.

I'm about to build a little test program to try TStringList. Let you know.

Thanks.
FPC 3.2.0, Lazarus IDE v2.0.4
 Windows 10 Pro 32-GB
 Intel i7 770K CPU 4.2GHz 32702MB Ram
GeForce GTX 1080 Graphics - 8 Gig
4.1 TB

JLWest

  • Hero Member
  • *****
  • Posts: 1293
Re: Strings Again
« Reply #24 on: December 08, 2018, 08:26:39 pm »
Code: Pascal  [Select][+][-]
  1.  function TForm1.ProcessOneRecord(aTFrec : String) : XferRecord;
  2.   Var
  3.     Lst : TStringList;
  4.     XFerRec : XferRecord;
  5.     TFRecord : String = '';
  6.     Field : String;
  7.     Flds : Integer;
  8.     Idx : Integer;
  9.   Begin
  10.    Lst := TStringList.Create;
  11.   try
  12.      Lst.CommaText := aTFrec;
  13.      Flds := Lst.Count;
  14.      XFerRec.TxtRec:= aTFrec;
  15.      XFerRec.Fields:= Flds;
  16.  
  17.     for Idx:= 0 to Lst.Count-1 do begin
  18.      Field :=  Lst[Idx];
  19.      XFerRec := UpdateXFerRecord(Field,Idx,XFerRec);
  20.      ShowField(Field);
  21.     end;
  22.   finally
  23.     Lst.Free;
  24.     Result := XFerRec;
  25.   end;
  26.  end;                              

Got this working great.
 
It's the "Lst.CommaText := aTFrec;" that does all the heavy lifting I think.

Have to try it on a record that looks like the following:

  'LAN,YSSY,NZAA,B789_LAN_LATAM, 0010,LA800,CC-BGA,0'

WOW.

Thanks

FPC 3.2.0, Lazarus IDE v2.0.4
 Windows 10 Pro 32-GB
 Intel i7 770K CPU 4.2GHz 32702MB Ram
GeForce GTX 1080 Graphics - 8 Gig
4.1 TB

garlar27

  • Hero Member
  • *****
  • Posts: 652
Re: Strings Again
« Reply #25 on: December 10, 2018, 04:48:24 pm »
Maybe it's a little late but
Have you tried something like this (though I don´t know how it will work if one field is missing):

Code: Pascal  [Select][+][-]
  1. uses CsvDocument;
  2.  
  3. type
  4.    TFlight = record
  5.       Field01: string;
  6.       Field02: string;
  7.       Field03: string;
  8.       Field04: string;
  9.       Field05: string;
  10.       Field06: string;
  11.       Field07: string;
  12.       Field08: string;
  13.       Field09: string;
  14.    end;
  15.  
  16. procedure ProcessData(const AFile: string);
  17. var
  18.    CSVDocument : TCSVDocument;
  19.    ind: Integer;
  20.    AFlight: TFlight;
  21. begin
  22.    CSVDocument := nil;
  23.    try
  24.       CSVDocument := TCSVDocument.Create;
  25.  
  26.       CSVDocument.LoadFromFile(AFile);
  27.       for ind := 1 to CSVDocument.RowCount - 1 do begin
  28.          AFlight.Field01 := Trim(CSVDocument.Cells[0,ind]);
  29.          AFlight.Field02 := Trim(CSVDocument.Cells[1,ind]);
  30.          AFlight.Field03 := Trim(CSVDocument.Cells[2,ind]);
  31.          AFlight.Field04 := Trim(CSVDocument.Cells[3,ind]);
  32.          AFlight.Field05 := Trim(CSVDocument.Cells[4,ind]);
  33.          AFlight.Field06 := Trim(CSVDocument.Cells[5,ind]);
  34.          AFlight.Field07 := Trim(CSVDocument.Cells[6,ind]);
  35.          AFlight.Field08 := Trim(CSVDocument.Cells[7,ind]);
  36.          AFlight.Field09 := Trim(CSVDocument.Cells[8,ind]);
  37.          // Do something with AFlight
  38.       end; {<--- del for ind }
  39.    finally
  40.       FreeAndNil(CSVDocument);
  41.    end;
  42. end;
  43.  

Almir.Bispo

  • Jr. Member
  • **
  • Posts: 91
  • CSV Comp DB is the Best NoSQL
    • CSV Comp DB (NoSQL)
Re: Strings Again
« Reply #26 on: December 10, 2018, 06:20:58 pm »
You can use this.The CSV Comp DB with CSV-Pascal Library (open source).You  must prefer semi-colon delimited file
free get on http://adltecnologia.blogspot.com.br
Look PowerFul Exemple below

Code: Pascal  [Select][+][-]
  1.  //ILDE-Pascal (open-source)
  2. {$i ...\CQL_TO_PASCAL.txt}
  3. procedure MycsvONDB;
  4. var myresult:Tstringlist;
  5.     cursor,db,id_table:string;
  6. begin
  7. myresult:=Tstrinlist.create;
  8. db :='c:\mydb';
  9. id_table :='MyTable'; //csv table
  10. //add CQL Command to run
  11. cursor :=  default_delimiter(db,id_table,',');//change ',' by default (';')  delimiter
  12. cursor := set_underline(db,id_table);         //change space key by underline (no data lost)
  13. //maybe ou need to list all data on column index 2 (or other)
  14. cursor := field_list(db,id_table,'Any',2); //all data is listed on MyTable.que
  15. CSV_COMP_DB_execute(cursor);//DB execution
  16. //now just load result
  17. while not ( fileexists('lock.inf') )do begin {wait start} end;
  18. while  ( fileexists('lock.inf') ) do begin {wait execution} end;
  19. //load
  20. myresult.loadfromfile(application.location + id_table + '.que');
  21. Memo1.text := myresult.text;
  22. myresult.free;
  23.  
  24. end;
  25.  

The exemple must  runs on same path of CSV Comp DB (Desktop version)
You can do Everthing with csv (Nosql Cloud technology,IOT,E-Commerce).
Everthing Free and Open
« Last Edit: December 10, 2018, 06:24:18 pm by Almir.Bispo »
CSV Comp DB Developer {Pascal Lover}

 

TinyPortal © 2005-2018