How to continue getline, find keywords.

I'm trying to read a set of numbers from a large text file, and write them into a second text file.

The text I have comes in a zillion blocks that looks like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
block {
 camera 26.7187500 299.531250 0.000000000;
 time 4:18.48760986m;
 setangle 30.9375000 -52.0312500 0.000000000;
 clientdata {
  uk_bit_b10;
  info1 0;
  info2 998;
  info3 1;
  info4 0;
  info5 0;
  info6 0;
  info7 0;
  info8 9;
 }
 updateentity {
  entity 1;
  frame 13;
  origin_x 1689.00000;
  origin_y -828.000000;
  origin_z 172.000000;
  angles_1 30.9375000;
  angles_2 -52.0312500;
 }
 updateentity {
  entity 2;
  frame 16;
  origin_x 1368.75000;
  origin_y -1015.75000;
  origin_z 344.000000;
  angles_1 -5.62500000;
 }
 updateentity {
  entity 3;
  frame 7;
  origin_x 1842.12500;
  origin_y -1009.87500;
  origin_z 20.0000000;
  angles_1 11.2500000;
  angles_2 -180.000000;
  angles_3 7.03125000;
 }
 updateentity {
  entity 14;
 }
}


Within each block I want the numbers from angles 123 listed under 'entity 3' to be written in a line in a text file.

I wrote out what is more or less pseudocode, and then started trying to write a program for it. I included my 'pseudocode' as comments.

The part I'm stuck on is how to read the file, and then when it encounters my key word, enter a separate sub-routine that continues scanning, but for different terms.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#include <iostream>
#include <fstream>
#include <string>

using namespace std;

int main()
{
    
int number;

string a1 = "0.000000000"; // Establish string variables a1, a2, and a3, set them to 0.000000000

string a2 = "0.000000000";

string a3 = "0.000000000";

string line; // At least one string for getline

string entity3 = "  entity 3;" // search word

readfile.open (data.txt);

ifstream readfile ("data.txt", ios::in); // Open a text file for reading, I can use a hard-coded name.

ofstream myfile ("angles.txt", ios::out | ios::app); // Create and open a different text file for writing, I can also use a hard-coded name.

if(readfile.is_open())  
    {

    while(!readfile.eof()) {
                             
          getline(readfile,line);
          if ((number == line.find(entity3, 0)) != string::npos) {
                      
// Enter a subroutine that continues scanning, but for '  angles_1', '  // angles_2', and '  angles_3'
// Also scan for '}'
// 
// if angles_1 is found, read the number after the space, and omit the semicolon it terminates with.
// For example: angles_1 -2.81250000;
// Read in -2.81250000 (exactly as it is written) to variable 'a1'
// 
// Keep reading and if angles_2 is found, read in its value to variable called //'a2'
// Keep reading and if angles_3 is found, read in its value to variable called //'a3'
// 
// The angles in the read file are always in consecutive order.
// 
// If a '}' is read then stop reading and:
// print the value of angles_1, angles_2, and angles_3 in order separated by a space on a line in the
// write file. Go to a newline when done.
//
// Should be just myfile  << a1 << " " << a2 << " " << a3 << std::endl;
//
// For example:
// 351.562500 104.062500 -7.03125000
// 
// Then reset the values of a1, a2, and a3 to 0.000000000
//  
// Now the subroutine can be exited and returned to the main routine of //searching for '  entity 3;'
                               
                      
                      }
                      
                      
                      
                      
                      else {
                           
                           continue; // ?
                           
                           }
          
          
          
    }
                          
    else
    cout<<"Unable to open this file."<<endl;
    
    }

myfile.close(); // Upon end of file, close read file, save write file
readfile.close();

 return 0; // exit program.
}


Thanks for any help.

Note: [code] probably ruined my nice neat formatting, and the preview button isn't working for me, so my apologies for the mess.
ok explain is this a homework problem(and has to be done a certain way), or just something you want to work (any way possible) ?

I'm getting you want the second file to look something like this.

entity 3
11.2500000
-180.000000
7.03125000
entity 14
...


I think your making this more complicated than needed but I don't know if I understand your project 100%.

maybe just a loop to
find next Entity #
get angles_1
get angles_2
get angles_3
write to file
repeat

How many values for entity # do you need to get ?
Do they repeat ?
Will you get angles_1 - 3 for all of them ?
ok explain is this a homework problem(and has to be done a certain way), or just something you want to work (any way possible) ?


Any way possible.

I'm getting you want the second file to look something like this.

1
2
3
4
5
6
entity 3
11.2500000
-180.000000
7.03125000
entity 14
...



You mean the write file? No, just like this:

11.2500000 -180.008000 7.03125000
351.562500 104.062500 -3.03432100
..

and so on.

I think your making this more complicated than needed


It's a distinct possibility, and one that I hope is true.

maybe just a loop to
find next Entity #
get angles_1
get angles_2
get angles_3
write to file
repeat


As long as it knows I only want the values from entity 3, and that if there is no entity 3 make the three values 0.000000000 for that line.

How many values for entity # do you need to get ?


Just one value for entity number, and I wish that value to be 3 in this case :-)

If you mean in the block, only 3 numbers (the angles). If an angle isn't present do a 0.000000000 for that angle.

Do they repeat ?


Not within a block. There are many, many blocks though.

Will you get angles_1 - 3 for all of them ?


Only for those listed under entity 3 in a block, then go to the next line in the write file, and start the process over for the next block.

There are many blocks in the read file, near 30,000 in fact. Performance may be a concern for the program, as notepad and wordpad can't seem to complete a simple search and replace on these files in under an hour. (OpenOffice Writer can do it in 20 minutes though!)

To make it more clear what I am trying to do is the following:

remove the setangle line, I think I can do this with search and replace, but if I come across some easy way to automate that I'd try to stick it in.

I want to replace the three values after 'camera' with the angles from entity 3, making them 0.000000000 if no entity 3 entry is seen in the block.

I figured I could do this by mining the values of entity 3, putting them in a new data file, and then making another program that reads from the readfile, looks for camera, and replaces its values with the ones in the new data file going line by line.

That was the simplest way I could think of doing it with my limited programming ability. If I got both programs working I could probably merge them into one.

There should be a simple way to do this, but I couldn't find any advanced word processors with such features, or databases that read from files.

Some complications I see is that each block needs to be scanned taking care to notice the curly brace terminators, and having it 'go back up' to 'camera' to adjust it with values that appear below it in the file. It's because that seems so difficult is why I'm doing it in what is likely a 'crude' way.
I guess what I didn't make clear, is each block going to have a entity 3, are you going to want the same entity values from each block ? So is it going to have multiple entity 3's or just one in the file ?

My last question is how many different entity #'s are you wanting to get data from ?
I guess what I didn't make clear, is each block going to have a entity 3


Nope, some blocks do not have an entity 3.

(and in that case I want 0.000000000 0.000000000 0.000000000 on the line for that block)

are you going to want the same entity values from each block ?


If the block features an entity 3, then I want its angles, from every block that features an entity 3.

There are 3 angles per entity at most. They are ordered from 1 to 3 always, even if an angle isn't presented. So for example you could see angle_2 and angle_3, and 3 would always be after 2.

So is it going to have multiple entity 3's or just one in the file ?


From the read file? There is never more than one entity 3 in a block.

There are many blocks, some have an entity 3 in them, some do not.

If you mean the write file, there will be a line printed for every single block that gets read.

Yikes, I just realized a problem, there won't be a line printed for every single block the way I'm doing it. So I need to scrap even what little code I've written.

I need to test for 'block' instead I guess, then enter a sub routine that reads the block, looks for entity 3, if it doesn't find it print the zeros, if it does get its angles if it has them.

I don't know if that's what you were getting at or not, but directly or indirectly you helped me realize this error. Much obliged.

My last question is how many different entity #'s are you wanting to get data from ?


Per block only one, if entity 3 is present, if not then 0.

Total entity number? Would be every block with an entity 3, of which there are thousands.
I couldn't get your code to work, so I tried to fix it with what I knew about the program at that time....

It does not write to file(it writes to screen) and does not check for block first...

Nope, some blocks do not have an entity 3.

(and in that case I want 0.000000000 0.000000000 0.000000000 on the line for that block)


Ok I understand now, wish I had read that a hour ago.... You will need to search for "block {" first and if found then look for the entity's you want....

No worries that's just one more loop...

So add a while loop for each block
If enity 3 is not found then set values to "0.000000000" and you should be good.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#include <iostream>
#include <fstream>
#include <string>
using namespace std;

int main()
{
// int number=0;
int count=0; // just for testing
int entity3found=0;
string a1 = "angles_1"; // Establish string variables a1, a2, and a3, set them to 0.000000000
string a2 = "angles_2";
string a3 = "angles_3";
string a1out;			// Used for output
string a2out;
string a3out;
string stop = "}";		
string fail = "0.000000000";  // May be used later... for each block
string entity3 = "  entity 3"; // search word
string line; // At least one string for getline
ifstream readfile ("data.txt", ios::in); // Open a text file for reading, I can use a hard-coded name.
ofstream myfile ("angles.txt", ios::out | ios::app); // Create and open a different text file for writing, I can also use a hard-coded name.

if (readfile.is_open())
	{
	while (readfile.good())
		{
		getline (readfile,line);
		count++; // just for testing
// 		cout << count << ": " << line << endl; // just for testing

	 	if (line.find(entity3) != string::npos)
			{
// 			cout << count << ": " << line << endl;  // just for testing
			entity3found=1;
			while (entity3found==1)
			{
			getline (readfile,line);
		 	if (line.find(a1) != string::npos)
				{
				a1out=line;
				if (a1out.size () > 0)
					{
					a1out.resize (a1out.size () - 1); 	// erase last char of string
					a1out.erase (0,11); 				// erase first 11 chars of string
					}
				}
		 	if (line.find(a2) != string::npos)
				{
				a2out=line;
				if (a2out.size () > 0)
					{
					a2out.resize (a2out.size () - 1); 	// erase last char of string
					a2out.erase (0,11); 				// erase first 11 chars of string
					}
				}
		 	if (line.find(a3) != string::npos)
				{
				a3out=line;
				if (a3out.size () > 0)
					{
					a3out.resize (a3out.size () - 1); 	// erase last char of string
					a3out.erase (0,11); 				// erase first 11 chars of string
					}
				}
				
			if (line.find(stop) != string::npos)
				{
				entity3found=0;
//				break;  // use the entity3found=0 or break to stop the loop.
				}

			}
				cout << a1out << " "<< a2out << " "<< a3out << endl;;
			
			}
		
		}
    }    
    
else
	{cout<<"Unable to open this file."<<endl;}

myfile.close(); // Upon end of file, close read file, save write file
readfile.close();

return 0; // exit program.
}

I'm overwhelmed. Thanks a million.

This kind of 'nested getline' was exactly the syntax I needed.

Will add that extra while loop soon as I understand this sufficiently, but in the mean time I wanted to say thanks :-)

Hey man, just wanted to say thanks again. I got the code to do what I want, but it involved butchering your wonderful work a bit.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
#include <iostream>
#include <fstream>
#include <string>
using namespace std;

int main()

{
    
ifstream readfile ("data.txt", ios::in); 

ofstream writefile ("angles.txt", ios::out | ios::app);

string a1 = "angles_1";

string a2 = "angles_2";

string a3 = "angles_3";

string stop = "}";		

string block = "block {";

string line;    

string a1out = "0.000000000";

string a2out = "0.000000000";

string a3out = "0.000000000";

string entity3 = "  entity 3;";

int count = 0;

int entity3found=0;

int blockfound = 0;

if (readfile.is_open())

{

while (readfile.good())

{

getline (readfile,line);

if (line.find(block) != string::npos)

{

blockfound = 1;   
               
while (blockfound==1)      

{
      
getline (readfile,line);

if (line.find(entity3) != string::npos)

{
                       
entity3found=1;

while (entity3found==1)

{
                  
getline (readfile,line);

if (line.find(a1) != string::npos)

{
                  
a1out=line;

if (a1out.size () > 0)

{

a1out.resize (a1out.size () - 1);

a1out.erase (0,11); 				

}

} // a1 end

if (line.find(a2) != string::npos)

{
                  
a2out=line;

if (a2out.size () > 0)

{

a2out.resize (a2out.size () - 1);

a2out.erase (0,11); 				

}

} // a2 end

if (line.find(a3) != string::npos)

{
                  
a3out=line;

if (a3out.size () > 0)

{

a3out.resize (a3out.size () - 1);

a3out.erase (0,11);				

}

} // a3 end

if (line.find(stop) != string::npos)

{
                    
entity3found = 0;

} // stop end
                  
} // while entity 3 found end

} // if line find entity 3 end

if ( line[0] == 125 )

{

writefile << a1out << " " << a2out << " " << a3out << endl;

a1out = "0.000000000";

a2out = "0.000000000";

a3out = "0.000000000";

blockfound = 0;
                    
}
      
}
                     
}

}


}

else

{

cout<<"Unable to open this file."<<endl;

}  

writefile.close();

readfile.close();

return 0;

}

Well, that was the goal, get something to dig through all that data.

I think I know what this should do, but dont' see how it does what you want. Did you test the below code ?

1
2
3
4
5
6
7
8
if ( line[0] == 125 )
{
writefile << a1out << " " << a2out << " " << a3out << endl;
a1out = "0.000000000";
a2out = "0.000000000";
a3out = "0.000000000";
blockfound = 0;
}

never mind, I see you changing the value of a1out and then resetting it to 0 when done.

At first I thought this was the code that would print out the "0.000000000".
Topic archived. No new replies allowed.