Recent

Author Topic: String probelm(Solved)  (Read 2516 times)

JLWest

  • Hero Member
  • *****
  • Posts: 1293
String probelm(Solved)
« on: February 24, 2023, 11:22:57 pm »
I have strings and I need to search the strings and return two items from the search.

Search for:  (|.| = |;  |:|[|,|:= |-) Search items delimited by bar and I can't use Char because some of the items are 2 char.

The string will look like:
'procedure Erase(var f: file );'
'protected procedure TLazLoggerLogGroupList.Remove(const AConfigName: string );'

Need to return the item found '(' and the position in the string;

In the first string it would be '(' and 16.
In the second example 5 items match the criteria but what I'm looking for is '(' and 49.

The probelm is its not always a '(' as the first item in the string. It could be any of the listed items.( (|.| = |;  |:|[|,|:= |-) )

I can't come up with a solution.

Thanks
« Last Edit: March 08, 2023, 07:16:45 am by JLWest »
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

speter

  • Sr. Member
  • ****
  • Posts: 314
Re: String probelm
« Reply #1 on: February 25, 2023, 01:35:21 am »
I'm not totally sure that I understand you search items, but how about this:

Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. const
  3.   fields : array of string = ('(', ' = ', '; ', ':', '[', ',', ':= ', '-');
  4. var
  5.   s,u : string;
  6.   a, i : integer;
  7.   found : boolean;
  8. begin
  9.   i := 0;
  10.   for s in memo_input.lines do
  11.     begin
  12.       found := false;
  13.       inc(i);
  14.       for u in fields do
  15.         begin
  16.           a := pos(u,s);
  17.           if a > 0 then
  18.             begin
  19.               memo_msgs.append(format('%d: found "%s" at pos %d',[i,u,a]));
  20.               found := true;
  21.               break;
  22.             end;
  23.         end;
  24.       if not found then
  25.         memo_msgs.append(format('%d: no matches',[i]));
  26.     end;
  27.   memo_msgs.append('finished');
  28. end;

cheers
S.
I climbed mighty mountains, and saw that they were actually tiny foothills. :)

JLWest

  • Hero Member
  • *****
  • Posts: 1293
Re: String probelm(Solved)
« Reply #2 on: February 25, 2023, 01:47:33 am »
@speter

I'll try this out.

What I have doesn't work well, and it pretty ugly.


Thanks for the reply.

Yea, I see how this works. Good solution I think. I'll have to modify it a little and test it out on about 3,100+ strings;

Thanks
« Last Edit: February 25, 2023, 02:34:30 am by JLWest »
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

Zvoni

  • Hero Member
  • *****
  • Posts: 1936
Re: String probelm
« Reply #3 on: February 25, 2023, 04:22:27 pm »
Look at the StrSpn/StrCSpn-API available in libc, or on Windows it‘s part of the OS
One System to rule them all, One Code to find them,
One IDE to bring them all, and to the Framework bind them,
in the Land of Redmond, where the Windows lie
---------------------------------------------------------------------
Code is like a joke: If you have to explain it, it's bad

Zvoni

  • Hero Member
  • *****
  • Posts: 1936
Re: String probelm
« Reply #4 on: February 25, 2023, 04:33:41 pm »
From a POV of a possible algorithm:
You want to find first occurrence of any of those special characters in your string.
1) run through your characters, and check each for first occurrence
2) keep the results somewhere in a key/value pair (Stringlist?), with following specialty: the returned position is the key, your character the value
3) when all characters are checked, sort the Stringlist!
Beware: it‘s a string-sort, meaning you might have to pad out the keys with leading zeros
4) the first key/value pair with key>0 is what you’re looking for

Might have some spare time on monday to write a prove of concept

Edit: or better: instead of using a key/value storage just check position.
characters with position 0 get discarded immediately, the first non zero keep in a „minimum“ variable. Any following positions if greater than minimum get discarded, if lesser than minimum, it becomes the new minimum
« Last Edit: February 25, 2023, 04:49:01 pm by Zvoni »
One System to rule them all, One Code to find them,
One IDE to bring them all, and to the Framework bind them,
in the Land of Redmond, where the Windows lie
---------------------------------------------------------------------
Code is like a joke: If you have to explain it, it's bad

jamie

  • Hero Member
  • *****
  • Posts: 5675
Re: String probelm
« Reply #5 on: February 25, 2023, 04:42:58 pm »
of course, you can haul in the "StrUtils" unit and have just about all you need to manipulating strings.

 it has PosEx that allows you to select your starting indexes which means you can chain on from the last PosEx search to the next.

 Also, I Believe there is a PStr function somewhere that does the same as the C version does.
The only true wisdom is knowing you know nothing

Zvoni

  • Hero Member
  • *****
  • Posts: 1936
Re: String probelm
« Reply #6 on: February 25, 2023, 04:50:23 pm »
of course, you can haul in the "StrUtils" unit and have just about all you need to manipulating strings.

 it has PosEx that allows you to select your starting indexes which means you can chain on from the last PosEx search to the next.

 Also, I Believe there is a PStr function somewhere that does the same as the C version does.
I was thinking about that, too, but IIRC that unit deals with PChar‘s, so i‘m a bit wary about it
One System to rule them all, One Code to find them,
One IDE to bring them all, and to the Framework bind them,
in the Land of Redmond, where the Windows lie
---------------------------------------------------------------------
Code is like a joke: If you have to explain it, it's bad

JLWest

  • Hero Member
  • *****
  • Posts: 1293
Re: String probelm
« Reply #7 on: February 25, 2023, 06:15:45 pm »
@Zvoni I think what you published is about right

What I'm trying to parse out of the strings is the name.

procedure AbandonSignalHandler(RtlSigNum: Integer );
procedure AddExitProc(Proc: TProcedure );
procedure Close(var f: file);
protected procedure TCustomComboBox.CloseUp virtual;
procedure ClrEol;

In each example I strip off everything before the name leaving the string to be parsed as follows:.

AbandonSignalHandler(RtlSigNum: Integer );
AddExitProc(Proc: TProcedure );
Close(var f: file);
CloseUp virtual;
ClrEol;

I first thought I could Copy2symb if I knew what the symbol was but I don't think I can.
Maybe all I need is the location of what ever the first symbol is. Then I could do a Name:=Copy(Astr,1,p);

Spector solution is working somewhat.



 
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: String probelm
« Reply #8 on: February 26, 2023, 06:30:09 pm »
@Zvoni

I implemented your code example in a demo. It has a problems.

With  'procedure TCustomComboBox.CloseUp virtual;' I strip away procedure and TCustomComboBox leaving
CloseUp virtual; I'm after the name CloseUp but a sName:=Copy(sCopy,1,(a-1)); returns: CloseUp virtual. So I add a '  ' (space) to the fields array. But in the search routine it finds the ';' before the space.

const
  fields : array of string = ('(', ' = ', '; ', ':', '[', ',', ':= ', '-', ' '); a := pos(u,s);

The code is doing a position search in a string for the items in the Fields array. What would be returned is dependent of what order the items are in the array.


I can think of two ways to solve this.
1. Search the string for each item in the Fields array. When one is found add it's pos and the item in a TStringList.

8, '  '
15,;
Then iterate thru the TStringlist returning the lowest number and associated item.  Hows that for ugly? or maybe go thru the string to be searched char at a time, comparing each char with the Fields arrays items. First hit gives the position and  item.





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

Zvoni

  • Hero Member
  • *****
  • Posts: 1936
Re: String probelm
« Reply #9 on: February 27, 2023, 09:03:14 am »
Proof of concept
Code: Pascal  [Select][+][-]
  1. program Project1;
  2. Uses SysUtils, Classes;
  3.  
  4. Var
  5.   Delimiters:String='(|.| = |;  |:|[|,|:= |-)';          //This is not making any sense
  6.   Source1:String='procedure Erase(var f: file );';
  7.   Source2:String='protected procedure TLazLoggerLogGroupList.Remove(const AConfigName: string );';
  8.  
  9. Var
  10.   MyPos:Integer;
  11.   MyChar:String;
  12. Function CleanUp(Const ASource:String):String;
  13. Var s:String;
  14. Begin
  15.   s:=ASource.Replace(' :',':',[rfReplaceAll]);
  16.   s:=s.Replace(': ',':',[rfReplaceAll]);
  17.   s:=s.Replace(' ;',';',[rfReplaceAll]);
  18.   s:=s.Replace('; ',';',[rfReplaceAll]);
  19.   s:=s.Replace('( ','(',[rfReplaceAll]);
  20.   s:=s.Replace(' (','(',[rfReplaceAll]);
  21.   s:=s.Replace(') ',')',[rfReplaceAll]);
  22.   s:=s.Replace(' )',')',[rfReplaceAll]);
  23.   s:=s.Replace('= ','=',[rfReplaceAll]);
  24.   s:=s.Replace(' =','=',[rfReplaceAll]);
  25.   s:=s.Replace(':= ',':=',[rfReplaceAll]);
  26.   s:=s.Replace(' :=',':=',[rfReplaceAll]);
  27.   Result:=s;
  28. end;
  29.  
  30. Function GetPosString(Var ASource:String;Const ADelimiters:String;Var APos:Integer):String;
  31. Var
  32.   i:Integer;
  33.   p:Integer;
  34.   MinPos:Integer;
  35.   MinChr:String;
  36. Begin
  37.   ASource:=CleanUp(ASource);
  38.   MinPos:=Length(ASource)+1;
  39.   Result:='';
  40.   MinChr:='';
  41.   For i:=1 To Length(ADelimiters) Do
  42.     Begin
  43.       p:=Pos(ADelimiters[i],ASource);
  44.       If (p>0) And (p<MinPos) Then
  45.          Begin
  46.            MinPos:=p;
  47.            MinChr:=ADelimiters[i];
  48.          end;
  49.     end;
  50.   APos:=MinPos;
  51.   Result:=MinChr;
  52. end;
  53.  
  54. Function GetPosition(Var ASource:String;Const ADelimiters:String;Var APosition:Integer):String;
  55. Var
  56.   i:Integer;
  57.   p:Integer;
  58.   d:String;
  59.   MinPos:Integer;
  60.   MinChr:String;
  61.   s:Array Of String;
  62. Begin
  63.   d:=ADelimiters.Replace(' ','');        //We don't need spaces, since we're cleaning up the Source
  64.   ASource:=CleanUp(ASource);
  65.   Result:='';
  66.   MinChr:='';
  67.   MinPos:=Length(ASource)+1;             //We're setting the "Fail"-Result to Source-Length+1
  68.   s:=ADelimiters.Split('|');             //Splitting the Delimiters
  69.   For i:=Low(s) To High(s) Do            //Run through your Delimiters
  70.     Begin
  71.       p:=Pos(s[i],ASource);              //Get Position
  72.       If (p>0) And (p<MinPos) Then
  73.          begin
  74.            MinPos:=p;
  75.            MinChr:=s[i]
  76.          end;
  77.     end;
  78.   APosition:=MinPos;
  79.   Result:=MinChr;
  80. End;
  81.  
  82. begin
  83.   MyChar:=GetPosition(Source1,Delimiters,MyPos);
  84.   Writeln('Char=',MyChar,' found at Pos.=',MyPos,' in cleaned up String=',Source1);
  85.   MyChar:=GetPosition(Source2,Delimiters,MyPos);
  86.   Writeln('Char=',MyChar,' found at Pos.=',MyPos,' in cleaned up String=',Source2);
  87.   MyChar:=GetPosString(Source1,'.(;',MyPos);
  88.   Writeln('Char=',MyChar,' found at Pos.=',MyPos,' in cleaned up String=',Source1);
  89.   MyChar:=GetPosString(Source2,'.(;',MyPos);
  90.   Writeln('Char=',MyChar,' found at Pos.=',MyPos,' in cleaned up String=',Source2);
  91. end.
  92.  

But there is something fishy with your Delimiters.
You're looking for opening Paranthesis, but not for closing?
Since when is a '-' a legal character in a Function-Header?
Since when can you use ':=' in a Function-Header?

CloseUp virtual;
This is wrong. There is a semicolon missing before virtual

If you really want parse out just the Function-Name, then '.', '(' and ';' is enough for Delimiters.
'.' if it's a Function of a class
'(' for the Parameters-List
';' if it's a function without parameters

If you want to parse out just the Name incl. Parameters-List, then use Delimiters '.():;'
'.' if it's a Function of a class
'(' for start of the Parameters-List
')' for end of Parameters-List
':' if it's a function
';' end of Function-header

Of course everytime you have to move your starting-position of "ASource" forward

Next: There is no reason to use an Array (or that thing with the Pipe-Symbols) at all. See my Function GetPosString
« Last Edit: February 27, 2023, 09:13:45 am by Zvoni »
One System to rule them all, One Code to find them,
One IDE to bring them all, and to the Framework bind them,
in the Land of Redmond, where the Windows lie
---------------------------------------------------------------------
Code is like a joke: If you have to explain it, it's bad

Zvoni

  • Hero Member
  • *****
  • Posts: 1936
Re: String probelm
« Reply #10 on: February 27, 2023, 10:05:12 am »
Proof of concept
Code: Pascal  [Select][+][-]
  1. program Project1;
  2. Uses SysUtils, Classes;
  3.  
  4. Var
  5.   Source1:String='procedure Erase(var f: file );';
  6.   Source2:String='protected procedure TLazLoggerLogGroupList.Remove(const AConfigName: string );virtual;';
  7.   Source3:String='Function SomeFunc:String;Overload;';
  8.  
  9. Var
  10.   MyChar:String='';
  11.   MyParam:String='';
  12. Function CleanUp(Const ASource:String):String;
  13. Var s:String;
  14. Begin
  15.   s:=ASource.Replace(' :',':',[rfReplaceAll]);
  16.   s:=s.Replace(': ',':',[rfReplaceAll]);
  17.   s:=s.Replace(' ;',';',[rfReplaceAll]);
  18.   s:=s.Replace('; ',';',[rfReplaceAll]);
  19.   s:=s.Replace('( ','(',[rfReplaceAll]);
  20.   s:=s.Replace(' (','(',[rfReplaceAll]);
  21.   s:=s.Replace(') ',')',[rfReplaceAll]);
  22.   s:=s.Replace(' )',')',[rfReplaceAll]);
  23.   s:=s.Replace('= ','=',[rfReplaceAll]);
  24.   s:=s.Replace(' =','=',[rfReplaceAll]);
  25.   s:=s.Replace(':= ',':=',[rfReplaceAll]);
  26.   s:=s.Replace(' :=',':=',[rfReplaceAll]);
  27.   Result:=s;
  28. end;
  29.  
  30. Function GetFuncHeaderParams(Var ASource:String;Var AParamList:String;Const ReturnModifier:Boolean=False):String;
  31. Var
  32.   p:Integer;
  33.   e:Integer;
  34.   ChrClass:String='.';
  35.   ChrBlank:String=' ';
  36.   ChrStartParam:String='(';
  37.   ChrEndParam:String=')';
  38.   ChrEndHeader:String=';';
  39.   s:String;
  40. Begin
  41.   ASource:=CleanUp(ASource);
  42.   s:=ASource;
  43.   Result:='';
  44.   AParamList:='';
  45.   p:=Pos(ChrClass,s);
  46.   If p>0 Then              //It's a qualified Function of a class
  47.       s:=copy(s,p+1,Length(s)-p)
  48.   Else                     //It's not a Function of a Class
  49.     Begin
  50.       p:=Pos(ChrBlank,s);  //Find the Blank
  51.       If p>0 Then s:=copy(s,p+1,Length(s)-p);
  52.     end;
  53.   p:=Pos(ChrStartParam,s);
  54.   If p>0 Then              //Function has Parameter-List
  55.     Begin
  56.       e:=Pos(ChrEndParam,s);
  57.       If e>p Then AParamList:=Copy(s,p+1,e-p-1);
  58.     end;
  59.   p:=Pos(ChrEndHeader,s);  //The rest of the Header
  60.   If p>0 Then
  61.     If ReturnModifier Then
  62.       Result:=s
  63.     Else
  64.       s:=Copy(s,1,p);
  65.   Result:=s;
  66. end;
  67.  
  68. begin
  69.   MyChar:=GetFuncHeaderParams(Source1,MyParam,False);
  70.   Writeln('Function-Name1=',MyChar,' from Source=',Source1,' with no Modifiers, Parameter-List=',MyParam);
  71.   MyChar:=GetFuncHeaderParams(Source2,MyParam,True);
  72.   Writeln('Function-Name2=',MyChar,' from Source=',Source2,' with Modifiers, Parameter-List=',MyParam);
  73.   MyChar:=GetFuncHeaderParams(Source3,MyParam,False);
  74.   Writeln('Function-Name3=',MyChar,' from Source=',Source3,' with no Modifiers, Parameter-List=',MyParam);
  75. end.
  76.  
One System to rule them all, One Code to find them,
One IDE to bring them all, and to the Framework bind them,
in the Land of Redmond, where the Windows lie
---------------------------------------------------------------------
Code is like a joke: If you have to explain it, it's bad

Zvoni

  • Hero Member
  • *****
  • Posts: 1936
Re: String probelm
« Reply #11 on: February 27, 2023, 11:43:39 am »
Slightly optimized. Now recognizes leading qualifiers ('protected' etc.)
Code: Pascal  [Select][+][-]
  1. program Project1;
  2. Uses SysUtils, Classes, StrUtils;
  3.  
  4. Var
  5.   Source1:String='protected procedure Erase( var f: file )  ;';
  6.   Source2:String='protected procedure TLazLoggerLogGroupList.Remove ( const AConfigName : string ) ; virtual;';
  7.   Source3:String='Function SomeFunc : String; Overload ; ';        
  8.  
  9. Var
  10.   MyChar:String='';
  11.   MyParam:String='';
  12.  
  13. Function CleanUp(Const ASource:String):String;
  14. Var
  15.   s:String;
  16.   c:Integer;
  17.   b:Integer=0;
  18. Begin
  19.   s:=ASource;
  20.   Repeat
  21.     b:=0;
  22.     s:=StringReplace(s,' :',':',[rfReplaceAll],c);
  23.     b:=b+c;
  24.     s:=StringReplace(s,': ',':',[rfReplaceAll],c);
  25.     b:=b+c;
  26.     s:=StringReplace(s,' ;',';',[rfReplaceAll],c);
  27.     b:=b+c;
  28.     s:=StringReplace(s,'; ',';',[rfReplaceAll],c);
  29.     b:=b+c;
  30.     s:=StringReplace(s,'( ','(',[rfReplaceAll],c);
  31.     b:=b+c;
  32.     s:=StringReplace(s,' (','(',[rfReplaceAll],c);
  33.     b:=b+c;
  34.     s:=StringReplace(s,') ',')',[rfReplaceAll],c);
  35.     b:=b+c;
  36.     s:=StringReplace(s,' )',')',[rfReplaceAll],c);
  37.     b:=b+c;
  38.     s:=StringReplace(s,'= ','=',[rfReplaceAll],c);
  39.     b:=b+c;
  40.     s:=StringReplace(s,' =','=',[rfReplaceAll],c);
  41.     b:=b+c;
  42.     s:=StringReplace(s,':= ',':=',[rfReplaceAll],c);
  43.     b:=b+c;
  44.     s:=StringReplace(s,' :=',':=',[rfReplaceAll],c);
  45.     b:=b+c;
  46.     s:=StringReplace(s,' [','[',[rfReplaceAll],c);
  47.     b:=b+c;
  48.     s:=StringReplace(s,'[ ','[',[rfReplaceAll],c);
  49.     b:=b+c;
  50.     s:=StringReplace(s,' ]',']',[rfReplaceAll],c);
  51.     b:=b+c;
  52.     s:=StringReplace(s,'] ',']',[rfReplaceAll],c);
  53.     b:=b+c;
  54.   until b=0;
  55.   Result:=s;
  56. end;
  57.  
  58. Function GetFuncHeaderParams(Var ASource:String;Var AParamList:String;Const ReturnModifier:Boolean=False):String;
  59. Var
  60.   p:Integer;
  61.   e:Integer;
  62.   l:Integer;
  63.   ChrClass:String='.';
  64.   ChrBlank:String=' ';
  65.   ChrStartParam:String='(';
  66.   ChrEndParam:String=')';
  67.   ChrEndHeader:String=';';
  68.   s:String;
  69. Begin
  70.   ASource:=CleanUp(ASource);
  71.   s:=ASource;
  72.   Result:='';
  73.   AParamList:='';
  74.   p:=Pos(ChrClass,s);
  75.   If p>0 Then              //It's a qualified Function of a class
  76.       s:=copy(s,p+1,Length(s)-p)
  77.   Else                     //It's not a Function of a Class
  78.     Begin
  79.       p:=Pos(ChrBlank,s);  //Find the Blank
  80.       If p>0 Then s:=copy(s,p+1,Length(s)-p);
  81.     end;
  82.   p:=Pos(ChrStartParam,s);
  83.   If p>0 Then              //Function has Parameter-List
  84.     Begin
  85.       e:=Pos(ChrEndParam,s);
  86.       If e>p Then AParamList:=Copy(s,p+1,e-p-1);
  87.     end;
  88.   p:=Pos(ChrEndHeader,s);  //The rest of the Header
  89.   If p>0 Then
  90.     If ReturnModifier Then
  91.       Result:=s
  92.     Else
  93.       s:=Copy(s,1,p);
  94.   p:=Pos(ChrStartParam,s);
  95.   //Function has no Parameters, so the only BLANK can be before the Function-Name
  96.   //OR Function has Parameters, checking the Blank is before the ParamList/FunctionName
  97.   If p>0 Then l:=p Else l:=Length(s);
  98.   e:=RPosEx(ChrBlank,s,l);
  99.   If e>0 Then s:=Copy(s,e+1,Length(s)-e);
  100.   Result:=s;        
  101. end;
  102.  
  103. begin
  104.   MyChar:=GetFuncHeaderParams(Source1,MyParam,False);
  105.   Writeln('Function-Name1=',MyChar,' from Source=',Source1,' with no Modifiers, Parameter-List=',MyParam);
  106.   MyChar:=GetFuncHeaderParams(Source2,MyParam,True);
  107.   Writeln('Function-Name2=',MyChar,' from Source=',Source2,' with Modifiers, Parameter-List=',MyParam);
  108.   MyChar:=GetFuncHeaderParams(Source3,MyParam,False);
  109.   Writeln('Function-Name3=',MyChar,' from Source=',Source3,' with no Modifiers, Parameter-List=',MyParam);
  110. end.

EDIT: Of course, this can be expanded to "recognize" conditional compilation or external calls, e.g. "Function Blablabla;{$IFDEF Windows} blubb{$ENDIF}"
« Last Edit: February 27, 2023, 12:28:29 pm by Zvoni »
One System to rule them all, One Code to find them,
One IDE to bring them all, and to the Framework bind them,
in the Land of Redmond, where the Windows lie
---------------------------------------------------------------------
Code is like a joke: If you have to explain it, it's bad

JLWest

  • Hero Member
  • *****
  • Posts: 1293
Re: String probelm
« Reply #12 on: February 27, 2023, 06:02:09 pm »
"But there is something fishy with your Delimiters.
You're looking for opening Paranthesis, but not for closing?
Since when is a '-' a legal character in a Function-Header?
Since when can you use ':=' in a Function-Header?"          You can't, your right but in an operator you can

 Yes, I only need to know if there is a left '(' and it's location. Because what I'm trying to parse out is the name of the function, procedure, Const, Var, Operator and  property.

 operator operator :=(AVariant: Variant ): TCaption;
 public property TControl.Action :  TBasicAction read GetAction write SetAction;
 public function TCollection.Add: TCollectionItem;

So I first strip away items in the string not needed:

   :=(AVariant: Variant ): TCaption;
   Action :  TBasicAction read GetAction write SetAction;
   Add: TCollectionItem;

I have a Testbed and 1,000+ different procedures but I can generate function, Const, Var, Operator or property data.

I'll download your code and run the data thru it. It will take me  a couple of days.
It looks like a lot of work to do all that.

Thank you.
 


 
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

Zvoni

  • Hero Member
  • *****
  • Posts: 1936
Re: String probelm
« Reply #13 on: February 28, 2023, 04:11:25 pm »
operator operator :=(AVariant: Variant ): TCaption;
 public property TControl.Action :  TBasicAction read GetAction write SetAction;
 public function TCollection.Add: TCollectionItem;

So I first strip away items in the string not needed:

   :=(AVariant: Variant ): TCaption;
   Action :  TBasicAction read GetAction write SetAction;
   Add: TCollectionItem;

I have a Testbed and 1,000+ different procedures but I can generate function, Const, Var, Operator or property data.

I'll download your code and run the data thru it. It will take me  a couple of days.
It looks like a lot of work to do all that.

Thank you.

OK, got you.
Yes, i can see my code failing there.

Anyway, it's an interesting excersize, so i came up with a "new" Version.
Difference: I parse from right to left, and i return all parts in each own "variable"
Feel free to test, comment, whatever, since i'm pretty sure i didn't catch all possible combinations

Code: Pascal  [Select][+][-]
  1. program Project1;
  2. Uses SysUtils, Classes, StrUtils;
  3.  
  4. Type
  5.   TrimSpaces=(enmLeft, enmRight, enmBoth);
  6.  
  7. Var
  8.   Source1:String='strict protected procedure Erase (const AConfigName : string ; var f: file ;AValue :Integer = 0 )  ; cdecl; overload ;';
  9.   Source2:String='protected procedure TLazLoggerLogGroupList.Remove ( const AConfigName : string ) ; virtual;';
  10.   Source3:String='Function SomeFunc : String; Overload ; ';
  11.   Source4:String='Operator  :=  ( ALeft:String; ARight : String ) :  TSomeThing ; Overload ;';
  12.   Source5:String='Procedure DoSomething ; Overload ; cdecl;';
  13.   Source6:String='Strict Private Property SomeProperty[i : integer ] :  TSomeType Read FSomeProp Write FSomeProp ; default ; ';
  14.   Source7:String='Public   Property SomeProp2 [x : String ] : TSomeOtherType ; default; ';
  15.   Source8:String='Published  Property SomeProp3 ; ';
  16.  
  17.   MyChar:String='';
  18.   MyParam:String='';
  19.   MyResult:String='';
  20.   MyClass:String='';
  21.   MyMethod:String='';
  22.   MyParamArray:TStringArray;
  23.   MyLeadModifiers:TStringArray;
  24.   MyTrailModifiers:TStringArray;
  25.  
  26. Const
  27.   Colon=':';
  28.   Semicolon=';';
  29.   CloseParanthesis=')';
  30.   OpenParanthesis='(';
  31.   CloseIndex=']';
  32.   OpenIndex='[';
  33.   ReadS=' read ';
  34.   WriteS=' write ';
  35.   Equal='=';
  36.   Dot='.';
  37.   Blank=' ';
  38.  
  39. Function CleanUp2(Const ASource:String;Const OldValue:TStringArray;Const ATrimType:TrimSpaces):String;
  40. Var
  41.   i:Integer;
  42.   a:String;
  43.   s:String;
  44.  
  45.   Function InternalReplace:String;
  46.   Begin
  47.     Result:=s.Replace(a,OldValue[i],[rfReplaceAll]);
  48.   end;
  49.  
  50. Begin
  51.   s:=ASource;
  52.   i:=Low(OldValue);
  53.   Repeat
  54.     Case ATrimType Of
  55.       enmLeft:  Begin
  56.                   a:=Blank+OldValue[i];
  57.                   s:=InternalReplace;
  58.                 end;
  59.       enmRight: Begin
  60.                   a:=OldValue[i]+Blank;
  61.                   s:=InternalReplace;
  62.                 end;
  63.       enmBoth:  Begin
  64.                   a:=Blank+OldValue[i];
  65.                   s:=InternalReplace;
  66.                   a:=OldValue[i]+Blank;
  67.                   s:=InternalReplace;
  68.                 end;
  69.     End;
  70.     Inc(i);
  71.   Until i>High(OldValue);
  72.   Result:=s;
  73. End;
  74.  
  75. Function Min(AValue:Array Of Integer):Integer;
  76. Var
  77.   i:Integer;
  78. Begin
  79.   If Low(AValue)=High(AValue) Then Exit(AValue[0]);               //Error. Only one Element. Return Value
  80.   For i:=Low(AValue)+1 To High(AValue) Do
  81.     If (AValue[i]>0) And (AValue[i]<Result) Then
  82.       Result:=AValue[i];
  83. end;
  84.  
  85. Function GetFuncHeaderParamsR(Var ASource:String;
  86.                               Var AParamArray:TStringArray;
  87.                               Var AParamList:String;
  88.                               Var AResultType:String;
  89.                               Var AClassName:String;
  90.                               Var AMethod:String;
  91.                               Var ALeadModifiers:TStringArray;
  92.                               Var ATrailModifiers:TStringArray):String;
  93. Var
  94.   i:Integer;
  95.   l:Integer;       //For Length of ASource
  96.   sc:Integer;      //For Semicolon
  97.   sc1:Integer;     //Save-Variable for old position of Semicolon
  98.   co:Integer;      //For Colon
  99.   cp:Integer;      //For closing Paranthesis
  100.   op:Integer;      //For opening Paranthesis
  101.   oi:Integer;      //For opening Index
  102.   ci:Integer;      //For closing Index
  103.   r:Integer;       //For read modifier
  104.   w:Integer;       //For write modifier.
  105.   dt:Integer;      //For Dot
  106.   bl:Integer;      //For Blank
  107.   bl1:Integer;     //Save-Variable for old position of Blank
  108.   //temp. Variables
  109.   t:Integer;
  110.   t1:String;
  111.   t2:String;
  112.   cc:String;
  113.   oo:String;
  114.   pc:Integer;
  115.   po:Integer;
  116.  
  117.  
  118.   Function InternalGetResultType:String;
  119.   Begin
  120.     t1:=Copy(ASource,co,l-co+1);
  121.     t1:=CleanUp2(t1,[Colon,SemiColon],enmBoth);
  122.     t2:=Copy(ASource,1,co-1);
  123.     AResultType:=Copy(t1,2,Pos(SemiColon,t1)-2);
  124.     Result:=t2+t1;
  125.   End;
  126.  
  127. Begin
  128.   //Remove leading/trailing Whitespace and remove duplicate spaces
  129.   ASource:=DelSpace1(Trim(ASource));
  130.   //We're starting from the right looking for ';', ':' and ')'
  131.   //----------------------------------------------------------
  132.   //Should return Length(ASource) --> Sanity-Check
  133.   l:=Length(ASource);
  134.   sc:=RPosEx(Semicolon,ASource,l);
  135.   If sc<l Then Exit('');     //ERROR! Missing last ';'
  136.  
  137.   co:=RPosEx(Colon,ASource,l);
  138.   //If cp=0 then no Parameter-List. op MUST also be 0.
  139.   //If cp>0 then op MUST also be >0.
  140.   //In case of cp>0 And op>0, co>cp MUST represent Function-Result (Colon right of closing Paranthesis)
  141.   //otherwise colon is inside Parameter-List, and it's a Procedure (No Result)
  142.   //If ci=0 Then no Index. oi MUST also be 0
  143.   //If ci>0 then oi MUST also be >0.
  144.   //In case of ci>0 and oi>0 it's a Property. cp and op MUST be 0. co>ci MUST represent the Type
  145.   //otherwise the colon is inside the Index, and we have an Error
  146.   //For Properties there must be 1 colon for the Type, and Optional a second colon if there is an Index
  147.   op:=RPosEx(OpenParanthesis,ASource,l);
  148.   cp:=RPosEx(CloseParanthesis,ASource,l);
  149.   oi:=RPosEx(OpenIndex,ASource,l);
  150.   ci:=RPosEx(CloseIndex,ASource,l);
  151.   If (cp=0) And (op>0) Then Exit('');      //ERROR
  152.   If (cp>0) And (op=0) Then Exit('');      //ERROR
  153.   If (ci=0) And (oi>0) Then Exit('');      //ERROR
  154.   If (ci>0) And (oi=0) Then Exit('');      //ERROR
  155.   //we're looking for the left most semicolon
  156.   Repeat
  157.     sc1:=sc;                             //Save the prior position of semicolon
  158.     sc:=RPosEx(Semicolon,ASource,sc-1);
  159.   until (sc<=cp) Or (sc<=co) Or (sc<=ci); //If no Parameter-List Or Index and no Result, sc can return 0
  160.   //------------------------------------------------------------
  161.   //We've reached either a colon, a closing Paranthesis, a closing Index or the beginning of the line.
  162.   //sc1 represents the last position of Semicolon. Everything right of it are trailing modifiers
  163.   //Getting trailing modifiers. "cdecl", "Overload", "Virtual", "default" etc.
  164.   If sc1<l then
  165.     Begin
  166.       t1:=Copy(ASource,sc1,l-sc1+1);
  167.       t1:=CleanUp2(t1,[SemiColon],enmBoth);
  168.       t2:=Copy(ASource,1,sc1-1);
  169.       ASource:=t2+t1;
  170.       ATrailModifiers:=t1.Split([SemiColon],TStringSplitOptions.ExcludeEmpty);
  171.       l:=Length(ASource);
  172.     End;
  173.   //End of getting trailing modifiers
  174.   //------------------------------------------------------------
  175.   //Getting Result-Type
  176.   //The following If-Conditions are mutually exclusive
  177.   //It's a function with Parameter-List or an operator
  178.   If (co>0) And (cp>0) And (co>cp) Then
  179.     Begin
  180.       ASource:=InternalGetResultType;
  181.       l:=Length(ASource);
  182.     end
  183.   //It's a Property with an Index. Checking for "Read"/"Write"-Modifiers
  184.   Else If (co>0) And (ci>0) And (co>ci) Then
  185.     Begin
  186.       t1:=Copy(ASource,co,l-co);
  187.       t1:=CleanUp2(t1,[SemiColon,Colon],enmBoth);
  188.       t2:=Copy(ASource,1,co-1);
  189.       ASource:=T2+t1;
  190.       l:=Length(ASource);
  191.       sc:=RPosEx(SemiColon,ASource,sc1);
  192.       If (sc>0) And (sc<=sc1) Then sc1:=sc;
  193.       r:=RPosEx(LowerCase(ReadS),LowerCase(ASource),l);
  194.       w:=RPosEx(LowerCase(WriteS),LowerCase(ASource),l);
  195.       t:=Min([r,w]);              //Which is the most left?
  196.       If t>0 Then                 //t=0 indicates no "read" and "write" modifier
  197.         AResultType:=Copy(ASource,co+1,t-co-1)
  198.       Else
  199.         AResultType:=Copy(ASource,co+1,sc1-co-1);
  200.     End
  201.   //It's a function without Parameter-List.
  202.   //Can't be an Operator
  203.   //It's a Property without Index
  204.   //There can't be any more colons
  205.   Else If (co>0) And (cp=0) And (ci=0) Then
  206.     Begin
  207.       ASource:=CleanUp2(InternalGetResultType,[Colon],enmBoth);
  208.       l:=Length(ASource);
  209.     end;
  210.   //End of Getting Result-Type
  211.   //------------------------------------------------------------
  212.   //Getting Parameter-List. It doesn't matter if Operator, Procedure or Function
  213.   //If it's an Index of a Property, we're using [] instead of ()
  214.   If (cp>0) Or (ci>0) Then              //It has Index or Parameter-List
  215.     Begin
  216.       If cp>0 Then
  217.         Begin
  218.           cc:=CloseParanthesis;
  219.           oo:=OpenParanthesis;
  220.           pc:=cp;
  221.           po:=op;
  222.         end
  223.       Else If ci>0 Then
  224.         Begin
  225.           cc:=CloseIndex;
  226.           oo:=OpenIndex;
  227.           pc:=ci;
  228.           po:=oi;
  229.         End;
  230.       t1:=Copy(ASource,pc,l-pc+1);
  231.       t1:=CleanUp2(t1,[cc,Colon,SemiColon],enmBoth);
  232.       t2:=Copy(ASource,1,pc-1);
  233.       ASource:=t2+t1;
  234.       l:=Length(ASource);
  235.       t1:=Copy(ASource,po,l-po+1);
  236.       t1:=CleanUp2(t1,[oo,cc,Colon,SemiColon,Equal],enmBoth);
  237.       t2:=Copy(ASource,1,po-1);
  238.       AParamList:=Copy(t1,2,Pos(cc,t1)-2);
  239.       AParamArray:=AParamList.Split([SemiColon],TStringSplitOptions.ExcludeEmpty);
  240.       ASource:=CleanUp2(t2+t1,[cc,oo],enmBoth);
  241.       l:=Length(ASource);
  242.     end;
  243.   //End of Getting Parameter-List
  244.   //------------------------------------------------------------
  245.   //It's a Procedure without Parameter-List or a Published Property
  246.   //Semicolon is the only legal Delimiter here
  247.   //There can't be anymore semicolons left of sc1
  248.   //Just cleaning up
  249.   If (co=0) And (cp=0) And (ci=0) Then
  250.     ASource:=CleanUp2(ASource,[SemiColon],enmBoth);
  251.   //------------------------------------------------------------
  252.   //Getting Method-Name
  253.   l:=Length(ASource);
  254.   sc:=RPosEx(SemiColon,ASource,sc1);
  255.   sc1:=sc;
  256.   cp:=RPosEx(CloseParanthesis,ASource,cp);
  257.   op:=RPosEx(OpenParanthesis,ASource,op);
  258.   ci:=RPosEx(CloseIndex,ASource,ci);
  259.   oi:=RPosEx(OpenIndex,ASource,oi);
  260.   co:=RPosEx(Colon,ASource,co);
  261.   //get the most left Position of either colon, open Paranthesis, open Index or Semicolon
  262.   t:=Min([sc1,op,oi,co]);
  263.   If t=0 Then Exit('');          //ERROR. There is something wrong
  264.   //Checking for a dot '.' if Method is part of a Class, Record, Object
  265.   //There can only be one Dot
  266.   dt:=RPosEx(Dot,ASource,t);
  267.   bl:=RPosEx(Blank,ASource,t);
  268.   If bl=0 Then Exit('');         //ERROR. "Procedure" etc. Missing
  269.   //THE NAME OF THE METHOD
  270.   If (dt>0) And (bl>0) And (bl<dt) Then   //It's part of a class, record, object
  271.     Begin
  272.       Result:=Copy(ASource,dt+1,t-dt-1);
  273.       AClassName:=Copy(ASource,bl+1,dt-bl-1);
  274.     end
  275.   Else If (bl>0) And (dt=0) Then
  276.     Result:=Copy(ASource,bl+1,t-bl-1);
  277.   //End of Getting Method-Name
  278.   //------------------------------------------------------------
  279.   //Getting the Method. "Procedure", "Function" etc.
  280.   If bl>0 Then bl1:=bl;            //Save the last Position of blank
  281.   //Check for next blank to the left
  282.   bl:=RPosEx(Blank,ASource,bl-1);
  283.   //Get Method
  284.   AMethod:=Copy(ASource,bl+1,bl1-bl-1);
  285.   //End of getting Method
  286.   //------------------------------------------------------------
  287.   //Getting leading modifiers
  288.   //If bl is >0 here then we have leading modifiers
  289.   If bl>0 Then
  290.     Begin
  291.       t1:=Copy(ASource,1,bl-1);
  292.       ALeadModifiers:=t1.Split([Blank],TStringSplitOptions.ExcludeEmpty);
  293.     End;
  294.   //End of getting leading modifiers
  295. End;
  296.  
  297. begin
  298.   MyChar:=GetFuncHeaderParamsR(Source6,MyParamArray,MyParam,MyResult,MyClass,MyMethod,MyLeadModifiers,MyTrailModifiers);
  299. end.
« Last Edit: February 28, 2023, 04:13:34 pm by Zvoni »
One System to rule them all, One Code to find them,
One IDE to bring them all, and to the Framework bind them,
in the Land of Redmond, where the Windows lie
---------------------------------------------------------------------
Code is like a joke: If you have to explain it, it's bad

Thaddy

  • Hero Member
  • *****
  • Posts: 13208
Re: String probelm
« Reply #14 on: February 28, 2023, 04:29:07 pm »
But there is something fishy with your Delimiters.
There is something fishy with variants.... Change it to a properly typed type instead. Variants are a stop gap escape not to have to write proper code.
« Last Edit: February 28, 2023, 04:31:41 pm by Thaddy »
I actually get compliments for being rude... (well, Dutch, but that is the same)

 

TinyPortal © 2005-2018