Recent

Author Topic: Getting info that is very volatile.  (Read 1715 times)

OC DelGuy

  • Full Member
  • ***
  • Posts: 121
Getting info that is very volatile.
« on: January 30, 2023, 12:09:57 am »
I have a textfile that holds a list that's like 900 lines long.

The bottom of the program has 4 lines as an example of that text file.  I then call the procedure Convert to convert the lines of the text file to a Data Structure.  This Data Structure is to be used for a different program that will use the information.

Here's my Sample Data:
Code: Text  [Select][+][-]
  1. 'Aike - Pop 75 (16 fams). Gov: Squire. Shrine to Deneir. Inn: The Blue Chimera. 4 farmers, 2 artisans, 8 laborers, 2 paupers. Trade: beef.'
  2. 'Aire View - Pop 312 (63 fams). Gov: Priest. Shrines to Ulutiu and Bhaal. Inn: The Lost Horn. Taverns: The Drunken Ogre, The Golden Arms. 16 farmers, 9 artisans, 32 laborers, 6 paupers. Trade: barley, corn.'
  3. 'Barwick-in-Elmet - Pop 369 (77 fams). Gov: Magistrate. Shrines to Iyachtu Xvim and Gwaeron Windstrom. Inn: The Crooked Orc. Taverns: The Blue Priest, The Dirty Serpent. 19 farmers, 12 artisans, 39 laborers, 8 paupers. Trade: corn, turnips.'
  4. 'Scorborough - Pop 341 (72 fams). Gov: Constable. Shrines to Nobanion and Ibrandul. Inn: The Wild Tankard. Taverns: The Wild Minstrel, The Wild Chimera. 18 farmers, 11 artisans, 36 laborers, 7 paupers. Trade: potatoes, pears.'
These 4 lines are taken straight from the large file.




This is my Data Structure and variable:
Code: Pascal  [Select][+][-]
  1. type
  2.   Village = Record
  3.     Name, Inn, Government : String;
  4.     Gods, Taverns, Trade  : Array [1..3] of String;
  5.     Population, Families, Farmers, Artisans, Laborers, Paupers : Integer;
  6.   end; {type Village}
  7.  
  8. var
  9.   Villages : Array [1..1000] of Village;
I've extracted some of the information and not any of the titles and superfluous information.  But the information for Gods, Inn, Taverns and Trade are so volatile that I haven't been able to nail them down. 


This is my output:
Code: Text  [Select][+][-]
  1. Village Name Fileline 1:  Aike  Population: 75  Government: Squire
  2. Families: 16  Farmers: 4  Artisans: 2  Laborers: 8  Paupers: 2
  3.   Trade: beef.
  4.  
  5.  
  6. Village Name Fileline 2:  Aire View  Population: 312  Government: Priest
  7. Families: 63  Farmers: 16  Artisans: 9  Laborers: 32  Paupers: 6
  8.   Trade: barley, corn.
  9.  
  10.  
  11. Village Name Fileline 3:  Barwick-in-Elmet  Population: 369  Government: Magistrate
  12. Families: 77  Farmers: 19  Artisans: 12  Laborers: 39  Paupers: 8
  13.   Trade: corn, turnips.
  14.  
  15.  
  16. Village Name Fileline 4:  Scorborough  Population: 341  Government: Constable
  17. Families: 72  Farmers: 18  Artisans: 11  Laborers: 36  Paupers: 7
  18.   Trade: potatoes, pears.

My problem is getting the Gods, Inn, Taverns and Trade info because it's all different sizes.
How do I get the Gods, Inn, Taverns and Trade info?



Here's my source:
Code: Pascal  [Select][+][-]
  1. program Villages900;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. uses
  6.   {$IFDEF UNIX}
  7.   cthreads,
  8.   {$ENDIF}
  9.  
  10.   {$IFDEF MSWINDOWS}
  11.     {$APPTYPE CONSOLE}
  12.   {$ENDIF}
  13.  
  14.   Classes, sysutils
  15.   { you can add units after this };
  16.  
  17. type
  18.   Village = Record
  19.     Name, Inn, Government : String;
  20.     Gods, Taverns, Trade  : Array [1..3] of String;
  21.     Population, Families, Farmers, Artisans, Laborers, Paupers : Integer;
  22.   end; {type Village}
  23.  
  24. var
  25.   Filename : Textfile;                          // Global Vairable
  26.   Recds    : Integer;                           // Global Vairable
  27.   Fileline : Array [1..1000] of String;         // Global Vairable
  28.   Villages : Array [1..1000] of Village;        // Global Vairable
  29.  
  30. Procedure GetVillageLines;  // Reading the raw villages into the string Fileline.
  31.   Begin
  32.     Assignfile(FileName, '900Vills.txt');
  33.     Recds :=1;
  34.     Try
  35.       Reset(filename);
  36.       While not EOF(Filename) do
  37.         Begin
  38.           ReadLn(filename, Fileline[Recds]);
  39.           Fileline[Recds]:=Trim(Fileline[Recds]);
  40.           Recds := Recds + 1;
  41.         end; {While}
  42.     finally
  43.     end; {Try}
  44.   End; {Proc GetVillageLines}
  45.  
  46. Procedure Convert;
  47.   Var
  48.     x, y, z : Integer;
  49.     j       : String;
  50.  
  51.   Begin
  52.     For x := 1 to Recds do
  53.       Begin
  54.         For z:=1 to Length(Fileline[x]) do
  55.           Begin
  56.             j:=LeftStr(Fileline[x],z);
  57.             If RightStr(j, 7) = ' - Pop ' then  // This string is the first guaranteed separator.
  58.               Begin                        // It is 7 characters long, all before it is the name.
  59.                 Villages[x].Name:=LeftStr(j,z-7);                  // Put the name in the Record.
  60.                 Villages[x].Population:=StrToInt(TrimRight(Copy(Fileline[x],z+1,3)));  // Population is also always
  61.               end; {if RightStr}                                         // a set distance from the above separator.
  62.             If copy(j,z,1)='(' then Villages[x].Families:=StrToInt(TrimRight(Copy(Fileline[x],z+1,2)));
  63.             If copy(Fileline[x],z,4)='Gov:' then y:=z+5; // Above line.  Families is always enclosed by parenthesis.
  64.             Villages[x].Government:=Copy(Fileline[x],y,3);
  65.                Case Villages[x].Government of
  66.                  'Con': Villages[x].Government:='Constable';        // Using Case of is kind of a cheat.
  67.                  'Cou': Villages[x].Government:='Council';          // I know the Leader types and thus only need
  68.                  'Gui': Villages[x].Government:='Guildmaster';      // 3 characters to determine this entry.
  69.                  'Jud': Villages[x].Government:='Judge';
  70.                  'Lor': Villages[x].Government:='Lord';
  71.                  'Mag': Villages[x].Government:='Magistrate';
  72.                  'May': Villages[x].Government:='Mayor';
  73.                  'Pri': Villages[x].Government:='Priest';
  74.                  'She': Villages[x].Government:='Sheriff';          // The if statements below.
  75.                  'Squ': Villages[x].Government:='Squire';           // Again, the numbers are always before
  76.                  'Tow': Villages[x].Government:='Townmaster';       // the label.  Trim is used to get rid of spaces
  77.                end;                                                 // when the number is only one digit.
  78.  
  79.             If copy(Fileline[x],z,5) = 'farme' then Villages[x].Farmers:=  StrToInt(trim(copy(Fileline[x],z-3,3)));
  80.             If copy(Fileline[x],z,5) = 'artis' then Villages[x].Artisans:= StrToInt(trim(copy(Fileline[x],z-3,3)));
  81.             If copy(Fileline[x],z,5) = 'labor' then Villages[x].Laborers:= StrToInt(trim(copy(Fileline[x],z-3,3)));
  82.             If copy(Fileline[x],z,5) = 'paupe' then Villages[x].Paupers:=  StrToInt(trim(copy(Fileline[x],z-3,3)));
  83.  
  84.             If copy(Fileline[x],z,5) = 'Trade' then Villages[x].Trade[1]:=RightStr(Fileline[x],Length(Fileline[x])-z-6);
  85.           end; {For z}
  86.  
  87.       end; {For x}
  88.  
  89.  
  90.     For x := 1 to Recds do            //  This loop is to display what I've done so far.
  91.       Begin
  92.         WriteLn('Village Name Fileline ',x,':  ',Villages[x].Name,
  93.                                 '  Population: ',Villages[x].Population,
  94.                                 '  Government: ',Villages[x].Government);
  95.  
  96.         WriteLn(  'Families: ',Villages[x].Families,
  97.                  '  Farmers: ',Villages[x].Farmers,
  98.                 '  Artisans: ',Villages[x].Artisans,
  99.                 '  Laborers: ',Villages[x].Laborers,
  100.                  '  Paupers: ',Villages[x].Paupers);
  101.         WriteLn(   '  Trade: ',Villages[x].Trade[1]);
  102.         WriteLn; WriteLn;
  103.       end; {For x}
  104.   end; {proc Convert}
  105.  
  106.  
  107. begin
  108.   {GetVillageLines;}
  109.   Fileline[1]:='Aike - Pop 75 (16 fams). Gov: Squire. Shrine to Deneir. Inn: The Blue Chimera. 4 farmers, 2 artisans, 8 laborers, 2 paupers. Trade: beef.';
  110.   Fileline[2]:='Aire View - Pop 312 (63 fams). Gov: Priest. Shrines to Ulutiu and Bhaal. Inn: The Lost Horn. Taverns: The Drunken Ogre, The Golden Arms. 16 farmers, 9 artisans, 32 laborers, 6 paupers. Trade: barley, corn.';
  111.   Fileline[3]:='Barwick-in-Elmet - Pop 369 (77 fams). Gov: Magistrate. Shrines to Iyachtu Xvim and Gwaeron Windstrom. Inn: The Crooked Orc. Taverns: The Blue Priest, The Dirty Serpent. 19 farmers, 12 artisans, 39 laborers, 8 paupers. Trade: corn, turnips.';
  112.   Fileline[4]:='Scorborough - Pop 341 (72 fams). Gov: Constable. Shrines to Nobanion and Ibrandul. Inn: The Wild Tankard. Taverns: The Wild Minstrel, The Wild Chimera. 18 farmers, 11 artisans, 36 laborers, 7 paupers. Trade: potatoes, pears.';
  113.   Recds:=4;
  114.   Convert;
  115.   ReadLn;
  116. end. {Program Villages}
Free Pascal Lazarus Version #: 2.2.4
Date: 24 SEP 2022
FPC Version: 3.2.2
Revision: Lazarus_2_2_4
x86_64-win64-win32/win64

jamie

  • Hero Member
  • *****
  • Posts: 6091
Re: Getting info that is very volatile.
« Reply #1 on: January 30, 2023, 12:44:26 am »
Looks like the results of an simple accounting program.

Also looks like home WORK!  :D

anyways, the ":" is the key to the start of a group.

The "." is the end of each line or segment for that group.

Some segments may have comma delimited entries, those would be specific depending on the Group type, I guess.

What I would do is just build strings using the ":" and "." as the delimiter.

When you encounter a ":" then you can update the current group name then following strings belong to it.

 If this was me, I would just put it all in a TTreeView  8)
The only true wisdom is knowing you know nothing

OC DelGuy

  • Full Member
  • ***
  • Posts: 121
Re: Getting info that is very volatile.
« Reply #2 on: January 30, 2023, 05:16:09 am »
Looks like the results of an simple accounting program.
If you mean the numbers, then yes.  But these numbers are only one or two digits in a series of numbers, or two or three digits in a series of numbers AND in a set distance from the delimiters (I did learn something: delimiters.  I was calling them separators).  AND they had spaces before and after the numbers.  Knowing exactly where they were made it easy and Trim made it super easy to turn them into Integers.

Also looks like home WORK!  :D
I can see where you'd think that, but no, I'm not in a class, and I have nobody to give me homework!  I don't have access to textbooks and have only things like tutorials here on the net, and videos.  And, of course, I have you.  Guys who know way more than me and are willing to answer a few (maybe a few too many) questions.

anyways, the ":" is the key to the start of a group.

The "." is the end of each line or segment for that group.
Yes, I thought so too.  The beginning ("Inn:") is easy enough.  But where I get stumped is the "."  When I looked for that, I get the last "." and the resulting string is from just after the "Inn:"  all the way to the end of the file (the last character in all the strings is ".".  I have no doubt it's "finding" the first ".", I just don't know how to stop it after the first and before any other ".".  And each time it finds another ".", it writes over the last "Finding".

Some segments may have comma delimited entries, those would be specific depending on the Group type, I guess.

What I would do is just build strings using the ":" and "." as the delimiter.

When you encounter a ":" then you can update the current group name then following strings belong to it.
I my head, I know all this.  It's making it stop looking after it finds the first "." that's eluding me.

If this was me, I would just put it all in a TTreeView  8)
Don't know what that is.  But I'll look it up.
Free Pascal Lazarus Version #: 2.2.4
Date: 24 SEP 2022
FPC Version: 3.2.2
Revision: Lazarus_2_2_4
x86_64-win64-win32/win64

dseligo

  • Hero Member
  • *****
  • Posts: 1196
Re: Getting info that is very volatile.
« Reply #3 on: January 30, 2023, 08:47:24 am »
Here you go, I think it's working for your example:
Code: Pascal  [Select][+][-]
  1. program Villages900;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. {$IFDEF MSWINDOWS}
  6.   {$APPTYPE CONSOLE}
  7. {$ENDIF}
  8.  
  9. uses
  10.   {$IFDEF UNIX}
  11.   cthreads,
  12.   {$ENDIF}
  13.  
  14.   Classes, sysutils
  15.   { you can add units after this };
  16.  
  17. type
  18.   Tgtt = Array [1..3] of String;
  19.  
  20.   Village = Record
  21.     Name, Inn, Government : String;
  22.     Gods, Taverns, Trade  : Tgtt;
  23.     Population, Families, Farmers, Artisans, Laborers, Paupers : Integer;
  24.   end; {type Village}
  25.  
  26. var
  27.   Filename : Textfile;                          // Global Vairable
  28.   Recds    : Integer;                           // Global Vairable
  29.   Fileline : Array [1..1000] of String;         // Global Vairable
  30.   Villages : Array [1..1000] of Village;        // Global Vairable
  31.   iCnt, iCnt2: Integer;
  32.  
  33. Procedure GetVillageLines;  // Reading the raw villages into the string Fileline.
  34.   Begin
  35.     Assignfile(FileName, '900Vills.txt');
  36.     Recds :=1;
  37.     Try
  38.       Reset(filename);
  39.       While not EOF(Filename) do
  40.         Begin
  41.           ReadLn(filename, Fileline[Recds]);
  42.           Fileline[Recds]:=Trim(Fileline[Recds]);
  43.           Recds := Recds + 1;
  44.         end; {While}
  45.     finally
  46.     end; {Try}
  47.   End; {Proc GetVillageLines}
  48.  
  49. Procedure Convert;
  50. Var x, iPos: Integer;
  51.     sTempLine, sPart: String;
  52.  
  53.   // Get next part where dot is separator.
  54.   procedure GetNextPart(var ALine: String; var APart: String);
  55.   var iPos2: Integer;
  56.   begin
  57.     iPos2 := Pos('.', ALine);
  58.     If iPos2 > 0 then begin
  59.       APart := Copy(ALine, 1, iPos2 - 1);
  60.       Delete(ALine, 1, iPos2);
  61.     end
  62.     else begin
  63.       APart := ALine;
  64.       ALine := '';
  65.     end;
  66.   end;
  67.  
  68.   // separate parts combined by ',' or ' and '
  69.   // I complicated it because I don't know if combination of 'and' and ',' are possible
  70.   // This could probably be simplified
  71.   procedure SeparatePart(APartValue: String; var AArray: Tgtt);
  72.   var i, iComma, iAnd: Integer;
  73.     procedure GetPartValue(APos, ASeparatorLength: Integer);
  74.     begin
  75.       AArray[i] := Copy(APartValue, 1, APos - 1);
  76.       inc(i);
  77.       Delete(APartValue, 1, APos + ASeparatorLength);
  78.     end;
  79.  
  80.   begin
  81.     i := 1;
  82.  
  83.     iComma := Pos(',', APartValue);
  84.     iAnd := Pos(' and ', APartValue);
  85.     repeat
  86.       If iComma = 0 then begin
  87.         If iAnd = 0 then begin
  88.           AArray[i] := APartValue;    // no comma no and
  89.           APartValue := '';
  90.         end
  91.         else
  92.           GetPartValue(iAnd, 4);     // only and
  93.       end
  94.       else begin
  95.         If iAnd = 0 then
  96.           GetPartValue(iComma, 1)    // only comma
  97.         else
  98.           If iAnd > iComma then
  99.             GetPartValue(iComma, 1)  // comma is first
  100.           else
  101.             GetPartValue(iAnd, 4);   // and is first
  102.       end;
  103.  
  104.       iComma := Pos(',', APartValue);
  105.       iAnd := Pos(' and ', APartValue);
  106.     until (iComma = 0) and (iAnd = 0) and (APartValue = '');
  107.   end;
  108.  
  109. Begin
  110.   For x := 1 to Recds do Begin
  111.     sTempLine := Fileline[x];
  112.  
  113.     // first part is guaranteed: name, population, families
  114.     GetNextPart(sTempLine, sPart);
  115.     iPos := Pos(' - Pop ', sPart); // This string is the first guaranteed separator.
  116.     Villages[x].Name := Copy(sPart, 1, iPos - 1); // Put the name in the Record.
  117.     Villages[x].Population := StrToInt(Trim(Copy(sPart, iPos + 7, 3)));  // Population is also always
  118.                                                                          // a set distance from the above separator.
  119.     Villages[x].Families := StrToInt(Trim(Copy(sPart, Pos('(', sPart) + 1, 2))); // Families is always enclosed by parenthesis.
  120.  
  121.     // other parts
  122.     While sPart <> '' do begin
  123.       If Pos('Gov:', sPart) > 0 then                   // Government part
  124.         Villages[x].Government := Copy(sPart, Pos('Gov:', sPart) + 5, MaxInt)
  125.       else
  126.       If Pos('Inn: ', sPart) > 0 then
  127.         Villages[x].Inn := Copy(sPart, Pos('Inn: ', sPart) + 5, MaxInt)
  128.       else
  129.       If Pos('Shrine to ', sPart) > 0 then
  130.         SeparatePart(Copy(sPart, Pos('Shrine to ', sPart) + 10, MaxInt), Villages[x].Gods)
  131.       else
  132.       If Pos('Shrines to ', sPart) > 0 then // different god part
  133.         SeparatePart(Copy(sPart, Pos('Shrines to ', sPart) + 11, MaxInt), Villages[x].Gods)
  134.       else
  135.       If Pos('Taverns: ', sPart) > 0 then
  136.         SeparatePart(Copy(sPart, Pos('Taverns: ', sPart) + 9, MaxInt), Villages[x].Taverns)
  137.       else
  138.       If Pos('Trade: ', sPart) > 0 then
  139.         SeparatePart(Copy(sPart, Pos('Trade: ', sPart) + 7, MaxInt), Villages[x].Trade)
  140.       else begin
  141.         If Pos('farme', sPart) > 0 then
  142.           Villages[x].Farmers := StrToInt(Trim(Copy(sPart, Pos('farme', sPart) - 3, 3)));
  143.  
  144.         If Pos('artis', sPart) > 0 then
  145.           Villages[x].Artisans := StrToInt(Trim(Copy(sPart, Pos('artis', sPart) - 3, 3)));
  146.  
  147.         If Pos('labor', sPart) > 0 then
  148.           Villages[x].Laborers := StrToInt(Trim(Copy(sPart, Pos('labor', sPart) - 3, 3)));
  149.  
  150.         If Pos('paupe', sPart) > 0 then
  151.           Villages[x].Paupers := StrToInt(Trim(Copy(sPart, Pos('paupe', sPart) - 3, 3)));
  152.       end;
  153.  
  154.       GetNextPart(sTempLine, sPart);
  155.     end;
  156.   end;
  157. end; {proc Convert}
  158.  
  159. begin
  160.   {GetVillageLines;}
  161.   Fileline[1]:='Aike - Pop 75 (16 fams). Gov: Squire. Shrine to Deneir. Inn: The Blue Chimera. 4 farmers, 2 artisans, 8 laborers, 2 paupers. Trade: beef.';
  162.   Fileline[2]:='Aire View - Pop 312 (63 fams). Gov: Priest. Shrines to Ulutiu and Bhaal. Inn: The Lost Horn. Taverns: The Drunken Ogre, The Golden Arms. 16 farmers, 9 artisans, 32 laborers, 6 paupers. Trade: barley, corn.';
  163.   Fileline[3]:='Barwick-in-Elmet - Pop 369 (77 fams). Gov: Magistrate. Shrines to Iyachtu Xvim and Gwaeron Windstrom. Inn: The Crooked Orc. Taverns: The Blue Priest, The Dirty Serpent. 19 farmers, 12 artisans, 39 laborers, 8 paupers. Trade: corn, turnips.';
  164.   Fileline[4]:='Scorborough - Pop 341 (72 fams). Gov: Constable. Shrines to Nobanion and Ibrandul. Inn: The Wild Tankard. Taverns: The Wild Minstrel, The Wild Chimera. 18 farmers, 11 artisans, 36 laborers, 7 paupers. Trade: potatoes, pears.';
  165.   Recds:=4;
  166.   Convert;
  167.  
  168.   // not part of converting
  169.   For iCnt := 1 to Recds do            //  This loop is to display what I've done so far.
  170.     Begin
  171.       WriteLn('Village Name Fileline ',iCnt,':  ',Villages[iCnt].Name,
  172.                               '  Population: ',Villages[iCnt].Population,
  173.                               '  Government: ',Villages[iCnt].Government);
  174.  
  175.       WriteLn(  '  Families: ',Villages[iCnt].Families,
  176.                '  Farmers: ',Villages[iCnt].Farmers,
  177.               '  Artisans: ',Villages[iCnt].Artisans,
  178.               '  Laborers: ',Villages[iCnt].Laborers,
  179.                '  Paupers: ',Villages[iCnt].Paupers);
  180.       WriteLn('  Inn: ', Villages[iCnt].Inn);
  181.  
  182.       Write(   '  Gods: ');
  183.       For iCnt2 := 1 to 3 do Write('''' + Villages[iCnt].Gods[iCnt2] + ''' ');
  184.       WriteLn;
  185.  
  186.       Write(   '  Taverns: ');
  187.       For iCnt2 := 1 to 3 do Write('''' + Villages[iCnt].Taverns[iCnt2] + ''' ');
  188.       WriteLn;
  189.  
  190.       Write(   '  Trade: ');
  191.       For iCnt2 := 1 to 3 do Write('''' + Villages[iCnt].Trade[iCnt2] + ''' ');
  192.       WriteLn;
  193.  
  194.       WriteLn;
  195.     end; {For iCnt}
  196.  
  197.   ReadLn;
  198. end. {Program Villages}

Thaddy

  • Hero Member
  • *****
  • Posts: 14215
  • Probably until I exterminate Putin.
Re: Getting info that is very volatile.
« Reply #4 on: January 30, 2023, 09:13:29 am »
Much easier is to  use shortstring, if that is acceptable to you:
Code: Pascal  [Select][+][-]
  1.     Name, Inn, Government : String[255];
  2.     Gods, Taverns, Trade  : Array [1..3] of String[255];
  3.  { or plain shortstring }
Specialize a type, not a var.

alpine

  • Hero Member
  • *****
  • Posts: 1038
Re: Getting info that is very volatile.
« Reply #5 on: January 30, 2023, 12:30:23 pm »
Although the dseligo program is working perfectly, I would like to propose another version for Convert procedure using a slightly different approach (with TStringHelper). That way It is a bit clearer and shorter, I believe.

Code: Pascal  [Select][+][-]
  1. procedure Convert;
  2. var
  3.   I, J, N: Integer;
  4.   A, B: TStringArray;
  5.   S, ST: AnsiString;
  6.   First: Boolean;
  7.  
  8.   // Assign array[1..3] of String from TStringArray
  9.   // Would be no need for it if Gods, Taverns, Trade were declared as TStringArray
  10.   procedure AssignTgtt(var Dest: Tgtt; const Src: TStringArray);
  11.   var
  12.     I: Integer;
  13.   begin
  14.     for I := 1 to Math.Min(Length(Dest), Length(Src)) do
  15.       Dest[I] := Src[Pred(I)];
  16.   end;
  17.  
  18. begin
  19.   for I := 1 to Recds do
  20.   begin
  21.     A := Fileline[I].Split(['.']);
  22.     First := True;
  23.     for S in A do
  24.     begin
  25.       ST := Trim(S);
  26.       if First then // Handle the first sentence
  27.       begin
  28.         B := ST.Split([' - Pop ', ' (', ' fams)']);
  29.         Villages[I].Name := B[0];
  30.         Villages[I].Population := StrToInt(B[1]);
  31.         Villages[I].Families := StrToInt(B[2]);
  32.         First := False;
  33.       end
  34.       else if ST.StartsWith('Gov:') then  // Handle Gov: ... .
  35.         Villages[I].Government := ST.Substring(5)
  36.       else if ST.StartsWith('Shrine') then // Handle Shrine(s) to ..., ... and ... .
  37.         AssignTgtt(Villages[I].Gods, Trim(ST.Substring(10)).Split([', ', ' and ']))
  38.       else if ST.StartsWith('Inn:') then // Handle Inn: ... .
  39.         Villages[I].Inn := ST.Substring(5)
  40.       else if ST.StartsWith('Taverns:') then // Handle Taverns: ..., ... .
  41.         AssignTgtt(Villages[I].Taverns, ST.Substring(9).Split([', ']))
  42.       else if ST.StartsWith('Trade:') then // Handle Trade: ..., ... .
  43.         AssignTgtt(Villages[I].Trade, ST.Substring(7).Split([', ']))
  44.       else if ST.Length > 0 then // Handle number of different villagers
  45.       begin
  46.         B := ST.Split([', ', ' ']);
  47.         for J := 0 to High(B) do
  48.           if Odd(J) then // Kind is at odd positions: 1, 3, ...
  49.             case B[J].Substring(0, 5) of
  50.               'farme': Villages[I].Farmers := N;
  51.               'artis': Villages[I].Artisans := N;
  52.               'labor': Villages[I].Laborers := N;
  53.               'paupe': Villages[I].Paupers := N;
  54.             end
  55.           else
  56.             N := StrToInt(Trim(B[J])); // number is at even: 0, 2, ...
  57.       end;
  58.     end;
  59.   end;
  60. end;
"I'm sorry Dave, I'm afraid I can't do that."
—HAL 9000

Thaddy

  • Hero Member
  • *****
  • Posts: 14215
  • Probably until I exterminate Putin.
Re: Getting info that is very volatile.
« Reply #6 on: January 30, 2023, 01:37:00 pm »
If you want to use the type helpers, why do not do it consistently?
There is a whole lot of rewrites to be done in that case, like for in do and obviously not this:
Code: Pascal  [Select][+][-]
  1.  N := StrToInt(Trim(B[J])); // number is at even: 0, 2, ...
But This:
Code: Pascal  [Select][+][-]
  1.  N := B[J].trim.ToInteger; // number is at even: 0, 2, ...
Also you declare the array as one based and "real programmers count from zero", so the test should be the other way around.
Try to be consistent in the way you use features.
« Last Edit: January 30, 2023, 01:58:54 pm by Thaddy »
Specialize a type, not a var.

alpine

  • Hero Member
  • *****
  • Posts: 1038
Re: Getting info that is very volatile.
« Reply #7 on: January 30, 2023, 06:19:28 pm »
Also you declare the array as one based and "real programmers count from zero", so the test should be the other way around.
I would recommend reading the posts more carefully before commenting.
"I'm sorry Dave, I'm afraid I can't do that."
—HAL 9000

Thaddy

  • Hero Member
  • *****
  • Posts: 14215
  • Probably until I exterminate Putin.
Re: Getting info that is very volatile.
« Reply #8 on: January 30, 2023, 06:42:29 pm »
I did. I would recommend to learn to count.
Specialize a type, not a var.

alpine

  • Hero Member
  • *****
  • Posts: 1038
Re: Getting info that is very volatile.
« Reply #9 on: January 30, 2023, 07:32:16 pm »
I did. I would recommend to learn to count.
Could you please be more specific, on which source line the counting is wrong?
"I'm sorry Dave, I'm afraid I can't do that."
—HAL 9000

OC DelGuy

  • Full Member
  • ***
  • Posts: 121
Re: Getting info that is very volatile.
« Reply #10 on: January 31, 2023, 01:44:31 am »
Here you go, I think it's working for your example:
Yes, it works for the four lines I supplied.  Hopefully I picked a good sample size so it covers all the possibilities.  I've only seen the first 100 lines and studied the first 50 lines (maybe).  But now, with this, I'll be able to figure out (hopefully) any anomalies.  And if not, then I'll just change the raw file for the few lines that might not fit right.

At any rate, thank you for this.



I'll be turning this in to my professor later.  :o
Just kidding!  That was for jamie in the first comment.  :D ;D

All seriousness aside:
Procedure in a procedure!!  Never seen nested procedures!  I've seen nested loops and if statements (which is why I like the Case statement).

And some stuff like the Pos function and Delete.  There's no mention of them in the Sysutils reference.




OK, I just ran it a few times with the txt file (the one with the 900 lines).  I got an exception error.  So I knew it had to be in the txt file.  So I did a Try..Except..End in the main block.  And in the Convert procedure, the first line after "For x := 1 to Recds do Begin" I added "xxline:=x;"

Code: Pascal  [Select][+][-]
  1.   Try
  2.     Convert;
  3.   Except
  4.     WriteLn('xxline :',xxline);
  5.   end;

xxline turned out to be 724.  Seems the only problem in the file was that line 723 was chopped off at the end.  One of the trades was actually in the line for the next village.  So, instead of starting off with the village name, it started with "copper. "  I opened the file with Notepad, looked for the offending village and simply put the copper back into the end of the previous line.  Now it runs beautifully for the full 900 lines.

So now I have a properly formatted Data file.

So, there you have it.  All I have to do now is write a WriteVillagedata (to file) procedure and run the file.  I'll also strip out all the WriteLn's and look for an exit code and terminate the program.

Clearly, I'm doing a bunch of extra stuff because in reality, all this is for a PDF I bought online that has, you guessed it, 900 village names.  I think I remember just highlighting the entire PDF and copying the text.  I then just opened Notepad and pasted.  That was the source for raw data.  Once I write the data file one time properly, I'm done.  I'll never have need for this program after the first successful run.

But I want to do all this extra work to learn.  Thanks to y'all, I learned quite a bit.

Yep, once I get the data file done, then I start writing an application that takes the information in the file and properly displays it on a form with the Lazarus controls and stuff.  And I'll have the information I need when I need it and searchable.  Need a village of about x number of population?  Here's a list of some.  Need a village that exports corn?  This list has those! 
Free Pascal Lazarus Version #: 2.2.4
Date: 24 SEP 2022
FPC Version: 3.2.2
Revision: Lazarus_2_2_4
x86_64-win64-win32/win64

OC DelGuy

  • Full Member
  • ***
  • Posts: 121
Re: Getting info that is very volatile.
« Reply #11 on: January 31, 2023, 01:50:41 am »
Although the dseligo program is working perfectly, I would like to propose another version for Convert procedure using a slightly different approach (with TStringHelper). That way It is a bit clearer and shorter, I believe.

WOW, when I ran this, I actually got several compile time errors.  I had just run the code above and it worked perfectly.  I got a runtime error, but solved that almost immediately.  So, I went with that code.  Thanks Alpine.
Free Pascal Lazarus Version #: 2.2.4
Date: 24 SEP 2022
FPC Version: 3.2.2
Revision: Lazarus_2_2_4
x86_64-win64-win32/win64

alpine

  • Hero Member
  • *****
  • Posts: 1038
Re: Getting info that is very volatile.
« Reply #12 on: January 31, 2023, 09:13:23 am »
Although the dseligo program is working perfectly, I would like to propose another version for Convert procedure using a slightly different approach (with TStringHelper). That way It is a bit clearer and shorter, I believe.

WOW, when I ran this, I actually got several compile time errors.  I had just run the code above and it worked perfectly.  I got a runtime error, but solved that almost immediately.  So, I went with that code.  Thanks Alpine.
You're welcome.
What I wanted to show is that it can first be split into sentences and then, depending on the position or prefix, split into individual tokens by specifying the delimiters. Thus processing should be easier than searching for specific positions.

I did. I would recommend to learn to count.
I see that total number of posts seems to be important and "real programmers" don't bother to explain their own offensive and otherwise false comments.
"I'm sorry Dave, I'm afraid I can't do that."
—HAL 9000

OC DelGuy

  • Full Member
  • ***
  • Posts: 121
Re: Getting info that is very volatile.
« Reply #13 on: January 31, 2023, 07:06:53 pm »
Alright!!  I finished the program!  Thanks to all of y'all!!

This is done like Julie Bowen and Plastic Surgery!!
Free Pascal Lazarus Version #: 2.2.4
Date: 24 SEP 2022
FPC Version: 3.2.2
Revision: Lazarus_2_2_4
x86_64-win64-win32/win64

 

TinyPortal © 2005-2018