Forum > General

Getting info that is very volatile.

(1/3) > >>

OC DelGuy:
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  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---'Aike - Pop 75 (16 fams). Gov: Squire. Shrine to Deneir. Inn: The Blue Chimera. 4 farmers, 2 artisans, 8 laborers, 2 paupers. Trade: beef.''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.''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.''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  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---type  Village = Record    Name, Inn, Government : String;    Gods, Taverns, Trade  : Array [1..3] of String;    Population, Families, Farmers, Artisans, Laborers, Paupers : Integer;  end; {type Village} var  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  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---Village Name Fileline 1:  Aike  Population: 75  Government: SquireFamilies: 16  Farmers: 4  Artisans: 2  Laborers: 8  Paupers: 2  Trade: beef.  Village Name Fileline 2:  Aire View  Population: 312  Government: PriestFamilies: 63  Farmers: 16  Artisans: 9  Laborers: 32  Paupers: 6  Trade: barley, corn.  Village Name Fileline 3:  Barwick-in-Elmet  Population: 369  Government: MagistrateFamilies: 77  Farmers: 19  Artisans: 12  Laborers: 39  Paupers: 8  Trade: corn, turnips.  Village Name Fileline 4:  Scorborough  Population: 341  Government: ConstableFamilies: 72  Farmers: 18  Artisans: 11  Laborers: 36  Paupers: 7  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  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---program Villages900; {$mode objfpc}{$H+} uses  {$IFDEF UNIX}  cthreads,  {$ENDIF}   {$IFDEF MSWINDOWS}    {$APPTYPE CONSOLE}  {$ENDIF}   Classes, sysutils  { you can add units after this }; type  Village = Record    Name, Inn, Government : String;    Gods, Taverns, Trade  : Array [1..3] of String;    Population, Families, Farmers, Artisans, Laborers, Paupers : Integer;  end; {type Village} var  Filename : Textfile;                          // Global Vairable  Recds    : Integer;                           // Global Vairable  Fileline : Array [1..1000] of String;         // Global Vairable  Villages : Array [1..1000] of Village;        // Global Vairable Procedure GetVillageLines;  // Reading the raw villages into the string Fileline.  Begin    Assignfile(FileName, '900Vills.txt');    Recds :=1;    Try      Reset(filename);      While not EOF(Filename) do        Begin          ReadLn(filename, Fileline[Recds]);          Fileline[Recds]:=Trim(Fileline[Recds]);          Recds := Recds + 1;        end; {While}    finally    end; {Try}  End; {Proc GetVillageLines} Procedure Convert;  Var    x, y, z : Integer;    j       : String;   Begin    For x := 1 to Recds do      Begin        For z:=1 to Length(Fileline[x]) do          Begin            j:=LeftStr(Fileline[x],z);            If RightStr(j, 7) = ' - Pop ' then  // This string is the first guaranteed separator.              Begin                        // It is 7 characters long, all before it is the name.                Villages[x].Name:=LeftStr(j,z-7);                  // Put the name in the Record.                Villages[x].Population:=StrToInt(TrimRight(Copy(Fileline[x],z+1,3)));  // Population is also always              end; {if RightStr}                                         // a set distance from the above separator.            If copy(j,z,1)='(' then Villages[x].Families:=StrToInt(TrimRight(Copy(Fileline[x],z+1,2)));            If copy(Fileline[x],z,4)='Gov:' then y:=z+5; // Above line.  Families is always enclosed by parenthesis.            Villages[x].Government:=Copy(Fileline[x],y,3);               Case Villages[x].Government of                 'Con': Villages[x].Government:='Constable';        // Using Case of is kind of a cheat.                 'Cou': Villages[x].Government:='Council';          // I know the Leader types and thus only need                 'Gui': Villages[x].Government:='Guildmaster';      // 3 characters to determine this entry.                 'Jud': Villages[x].Government:='Judge';                 'Lor': Villages[x].Government:='Lord';                 'Mag': Villages[x].Government:='Magistrate';                 'May': Villages[x].Government:='Mayor';                 'Pri': Villages[x].Government:='Priest';                 'She': Villages[x].Government:='Sheriff';          // The if statements below.                 'Squ': Villages[x].Government:='Squire';           // Again, the numbers are always before                 'Tow': Villages[x].Government:='Townmaster';       // the label.  Trim is used to get rid of spaces               end;                                                 // when the number is only one digit.             If copy(Fileline[x],z,5) = 'farme' then Villages[x].Farmers:=  StrToInt(trim(copy(Fileline[x],z-3,3)));            If copy(Fileline[x],z,5) = 'artis' then Villages[x].Artisans:= StrToInt(trim(copy(Fileline[x],z-3,3)));            If copy(Fileline[x],z,5) = 'labor' then Villages[x].Laborers:= StrToInt(trim(copy(Fileline[x],z-3,3)));            If copy(Fileline[x],z,5) = 'paupe' then Villages[x].Paupers:=  StrToInt(trim(copy(Fileline[x],z-3,3)));             If copy(Fileline[x],z,5) = 'Trade' then Villages[x].Trade[1]:=RightStr(Fileline[x],Length(Fileline[x])-z-6);          end; {For z}       end; {For x}      For x := 1 to Recds do            //  This loop is to display what I've done so far.      Begin        WriteLn('Village Name Fileline ',x,':  ',Villages[x].Name,                                '  Population: ',Villages[x].Population,                                '  Government: ',Villages[x].Government);         WriteLn(  'Families: ',Villages[x].Families,                 '  Farmers: ',Villages[x].Farmers,                '  Artisans: ',Villages[x].Artisans,                '  Laborers: ',Villages[x].Laborers,                 '  Paupers: ',Villages[x].Paupers);        WriteLn(   '  Trade: ',Villages[x].Trade[1]);        WriteLn; WriteLn;      end; {For x}  end; {proc Convert}  begin  {GetVillageLines;}  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.';  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.';  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.';  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.';  Recds:=4;  Convert;  ReadLn;end. {Program Villages}

jamie:
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)

OC DelGuy:

--- Quote from: jamie on January 30, 2023, 12:44:26 am ---Looks like the results of an simple accounting program.
--- End quote ---
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.


--- Quote from: jamie on January 30, 2023, 12:44:26 am ---Also looks like home WORK!  :D
--- End quote ---
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.


--- Quote from: jamie on January 30, 2023, 12:44:26 am ---anyways, the ":" is the key to the start of a group.

The "." is the end of each line or segment for that group.
--- End quote ---
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".


--- Quote from: jamie on January 30, 2023, 12:44:26 am ---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.

--- End quote ---
I my head, I know all this.  It's making it stop looking after it finds the first "." that's eluding me.


--- Quote from: jamie on January 30, 2023, 12:44:26 am ---If this was me, I would just put it all in a TTreeView  8)

--- End quote ---
Don't know what that is.  But I'll look it up.

dseligo:
Here you go, I think it's working for your example:

--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---program Villages900; {$mode objfpc}{$H+} {$IFDEF MSWINDOWS}  {$APPTYPE CONSOLE}{$ENDIF} uses  {$IFDEF UNIX}  cthreads,  {$ENDIF}   Classes, sysutils  { you can add units after this }; type  Tgtt = Array [1..3] of String;   Village = Record    Name, Inn, Government : String;    Gods, Taverns, Trade  : Tgtt;    Population, Families, Farmers, Artisans, Laborers, Paupers : Integer;  end; {type Village} var  Filename : Textfile;                          // Global Vairable  Recds    : Integer;                           // Global Vairable  Fileline : Array [1..1000] of String;         // Global Vairable  Villages : Array [1..1000] of Village;        // Global Vairable  iCnt, iCnt2: Integer; Procedure GetVillageLines;  // Reading the raw villages into the string Fileline.  Begin    Assignfile(FileName, '900Vills.txt');    Recds :=1;    Try      Reset(filename);      While not EOF(Filename) do        Begin          ReadLn(filename, Fileline[Recds]);          Fileline[Recds]:=Trim(Fileline[Recds]);          Recds := Recds + 1;        end; {While}    finally    end; {Try}  End; {Proc GetVillageLines} Procedure Convert;Var x, iPos: Integer;    sTempLine, sPart: String;   // Get next part where dot is separator.  procedure GetNextPart(var ALine: String; var APart: String);  var iPos2: Integer;  begin    iPos2 := Pos('.', ALine);    If iPos2 > 0 then begin      APart := Copy(ALine, 1, iPos2 - 1);      Delete(ALine, 1, iPos2);    end    else begin      APart := ALine;      ALine := '';    end;  end;   // separate parts combined by ',' or ' and '  // I complicated it because I don't know if combination of 'and' and ',' are possible  // This could probably be simplified  procedure SeparatePart(APartValue: String; var AArray: Tgtt);  var i, iComma, iAnd: Integer;    procedure GetPartValue(APos, ASeparatorLength: Integer);    begin      AArray[i] := Copy(APartValue, 1, APos - 1);      inc(i);      Delete(APartValue, 1, APos + ASeparatorLength);    end;   begin    i := 1;     iComma := Pos(',', APartValue);    iAnd := Pos(' and ', APartValue);    repeat      If iComma = 0 then begin        If iAnd = 0 then begin          AArray[i] := APartValue;    // no comma no and          APartValue := '';        end        else          GetPartValue(iAnd, 4);     // only and      end      else begin        If iAnd = 0 then          GetPartValue(iComma, 1)    // only comma        else          If iAnd > iComma then            GetPartValue(iComma, 1)  // comma is first          else            GetPartValue(iAnd, 4);   // and is first      end;       iComma := Pos(',', APartValue);      iAnd := Pos(' and ', APartValue);    until (iComma = 0) and (iAnd = 0) and (APartValue = '');  end; Begin  For x := 1 to Recds do Begin    sTempLine := Fileline[x];     // first part is guaranteed: name, population, families    GetNextPart(sTempLine, sPart);    iPos := Pos(' - Pop ', sPart); // This string is the first guaranteed separator.    Villages[x].Name := Copy(sPart, 1, iPos - 1); // Put the name in the Record.    Villages[x].Population := StrToInt(Trim(Copy(sPart, iPos + 7, 3)));  // Population is also always                                                                         // a set distance from the above separator.    Villages[x].Families := StrToInt(Trim(Copy(sPart, Pos('(', sPart) + 1, 2))); // Families is always enclosed by parenthesis.     // other parts    While sPart <> '' do begin      If Pos('Gov:', sPart) > 0 then                   // Government part        Villages[x].Government := Copy(sPart, Pos('Gov:', sPart) + 5, MaxInt)      else      If Pos('Inn: ', sPart) > 0 then        Villages[x].Inn := Copy(sPart, Pos('Inn: ', sPart) + 5, MaxInt)      else      If Pos('Shrine to ', sPart) > 0 then        SeparatePart(Copy(sPart, Pos('Shrine to ', sPart) + 10, MaxInt), Villages[x].Gods)      else      If Pos('Shrines to ', sPart) > 0 then // different god part        SeparatePart(Copy(sPart, Pos('Shrines to ', sPart) + 11, MaxInt), Villages[x].Gods)      else      If Pos('Taverns: ', sPart) > 0 then        SeparatePart(Copy(sPart, Pos('Taverns: ', sPart) + 9, MaxInt), Villages[x].Taverns)      else      If Pos('Trade: ', sPart) > 0 then        SeparatePart(Copy(sPart, Pos('Trade: ', sPart) + 7, MaxInt), Villages[x].Trade)      else begin        If Pos('farme', sPart) > 0 then          Villages[x].Farmers := StrToInt(Trim(Copy(sPart, Pos('farme', sPart) - 3, 3)));         If Pos('artis', sPart) > 0 then          Villages[x].Artisans := StrToInt(Trim(Copy(sPart, Pos('artis', sPart) - 3, 3)));         If Pos('labor', sPart) > 0 then          Villages[x].Laborers := StrToInt(Trim(Copy(sPart, Pos('labor', sPart) - 3, 3)));         If Pos('paupe', sPart) > 0 then          Villages[x].Paupers := StrToInt(Trim(Copy(sPart, Pos('paupe', sPart) - 3, 3)));      end;       GetNextPart(sTempLine, sPart);    end;  end;end; {proc Convert} begin  {GetVillageLines;}  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.';  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.';  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.';  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.';  Recds:=4;  Convert;   // not part of converting  For iCnt := 1 to Recds do            //  This loop is to display what I've done so far.    Begin      WriteLn('Village Name Fileline ',iCnt,':  ',Villages[iCnt].Name,                              '  Population: ',Villages[iCnt].Population,                              '  Government: ',Villages[iCnt].Government);       WriteLn(  '  Families: ',Villages[iCnt].Families,               '  Farmers: ',Villages[iCnt].Farmers,              '  Artisans: ',Villages[iCnt].Artisans,              '  Laborers: ',Villages[iCnt].Laborers,               '  Paupers: ',Villages[iCnt].Paupers);      WriteLn('  Inn: ', Villages[iCnt].Inn);       Write(   '  Gods: ');      For iCnt2 := 1 to 3 do Write('''' + Villages[iCnt].Gods[iCnt2] + ''' ');      WriteLn;       Write(   '  Taverns: ');      For iCnt2 := 1 to 3 do Write('''' + Villages[iCnt].Taverns[iCnt2] + ''' ');      WriteLn;       Write(   '  Trade: ');      For iCnt2 := 1 to 3 do Write('''' + Villages[iCnt].Trade[iCnt2] + ''' ');      WriteLn;       WriteLn;    end; {For iCnt}   ReadLn;end. {Program Villages}

Thaddy:
Much easier is to  use shortstring, if that is acceptable to you:
--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---    Name, Inn, Government : String[255];    Gods, Taverns, Trade  : Array [1..3] of String[255]; { or plain shortstring }

Navigation

[0] Message Index

[#] Next page

Go to full version