Forum > General
Getting info that is very volatile.
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