Jump to content
  • Advertisement
Sign in to follow this  
bargasteh

Reading and parsing a text file

This topic is 4680 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello I have been trying to parse my text file since 2 days ago, I can easily do this with Java but I have been having hard time to do it on C++ I have a file like this: Object1{ 0<0.05,0.455> 1<0.1,0.455> 2<0.15,0.455> 3<0.2,0.455> 4<0.25,0.455> 5<0.3,0.455> 6<0.35,0.455> 7<0.4,0.455> . . . etc Object1} Texture1{ . . . Texture1} Object1 start with { and end with }. the first number next to "<" is number of my node and first number is position X and second one is position Y. Now I want to put those Xs and Ys in a string vector and draw them later, the only thing I need is to start reading file where ever i see Object1{ and stop when I see Object1}. I will also tokenise each line to get X and Y. I will then have texture and so on. It is similare to XML but at this stage I want to keep it simple. Could you please help me to figure out what to do ? I this it will be something like this (for first line my text file): Loop throught file if (String = "Object1{" { read next line; get the size of string; loop throught it to find the first character "<" String 1 = 0; String 2 = 0.05,0.455> loop again to get "," String 1 = 0.05 String 2 = 0.455> loop again to get ">" String 1: 0.455 Any help is appreciated, I thank you so much in advance. Thanks

Share this post


Link to post
Share on other sites
Advertisement
I've had to tackle similar problems and the best way I know is to build a state machine-type parser and save your values in a vector of structs or just a simple vector of floats.

However, you might be able to more quicky hack something together by using the stream.ignore() and stream.get() members.


// Check these stdlibs.
#include <fstream>
#include <iostream>
#include <limits>
#include <vector>

// Ref characters and buffer, holds up to 9 characters.
std::string digitch_ = "0123456789";
char buffer[9];

std::ifstream stream;
std::string my_file = "my_file.txt";
stream.open(my_file.c_str());
char ch;
std::vector<float> vFloat;

// Need to loop here to end of file.
while (stream.get(ch))
{
if (digitch_.find( ch ) != std::string::npos)
// Read and parses each line beginning with a digit.
{
stream.ignore(std::numeric_limits<std::streamsize>::max(),'<'); // Ignores to '<'

stream.get(buffer,10,','); // Gets to next ','
vFloat.push_back(atof(buffer)); // Adds to vFloat.

stream.get(buffer,10,'>'); // Gets to next '>'
vFloat.push_back(atof(buffer)); // Adds to vFloat.

stream.ignore(std::numeric_limits<std::streamsize>::max(),'\n'); // Ignores to end of line.
}
else
// Just ignores everything else.
{
stream.ignore(std::numeric_limits<std::streamsize>::max(),'\n'); // Ignores line completely.
}
}







I've just thrown down some quick code, you might need to clean it up for your purposes. Good luck!

Edit: Found some mistakes, please note code revisions. A little too fast putting it down to paper!

[Edited by - random_thinker on August 28, 2005 10:13:04 AM]

Share this post


Link to post
Share on other sites
I can really use this technique, because I need to check the header of each section such as Object1, Texture, etc

Is there anybody who have other ideas?

Share this post


Link to post
Share on other sites
why not write extraction (the >>) operators for your Object1 type?
you know how you can do this?
int i;
cin>>i;

Why not do this?
MyType mt;
cin>>mt;

Nice huh? Forget tokenizing and all of that complex stuff. Oh and I'm assuming that you can change your data format a little, to make things easier:

Object
v 0.05 0.455
v 0.1 0.455
v 0.15 0.455
v 0.2 0.455
v 0.25 0.455
v 0.3 0.455
v 0.35 0.455
v 0.4 0.455
ObjectEnd


Ok here is the code:


struct Vertex
{
float x,y;
}
istream& operator>> (istream& stream, Vertex& v)
{
stream>>v.x;
stream>>v.y;
return stream;
}

struct Object
{
vector<Vertex> vertices;
};
istream& operator>> (istream& stream, Object& o)
{
string s;
Vertex v;
while(true)
{
stream>>s;
if(s=="v")
{
stream>>v;
o.vertices.push_back(v);
}
else
return;
}

//now how to use it:
ifstream fin("objects and textures.txt");
vector<Object> objects;
vector<Texture> textures;
string s;
fin>>s;
if(s=="Object")
{
Object o;
fin>>o;
objects.push_back(o);
}
else if (s=="Texture");
{
Texture t;
fin>>t; //you're going to have to write this one yourself
textures.push_back(t);
}





Share this post


Link to post
Share on other sites
Quote:
Original post by bargasteh
Hello

I have been trying to parse my text file since 2 days ago, I can easily do this with Java but I have been having hard time to do it on C++

I have a file like this:

Object1{
0<0.05,0.455>
1<0.1,0.455>
2<0.15,0.455>
3<0.2,0.455>
4<0.25,0.455>
5<0.3,0.455>
6<0.35,0.455>
7<0.4,0.455>
.
.
.
etc
Object1}

Texture1{
.
.
.
Texture1}


Object1 start with { and end with }.
the first number next to "<" is number of my node and first number is position X and second one is position Y.

Now I want to put those Xs and Ys in a string vector and draw them later, the only thing I need is to start reading file where ever i see Object1{ and stop when I see Object1}. I will also tokenise each line to get X and Y.
I will then have texture and so on. It is similare to XML but at this stage I want to keep it simple.

Could you please help me to figure out what to do ?

I this it will be something like this (for first line my text file):

Loop throught file

if (String = "Object1{" {

read next line;
get the size of string;
loop throught it to find the first character "<"
String 1 = 0;
String 2 = 0.05,0.455>
loop again to get ","
String 1 = 0.05
String 2 = 0.455>
loop again to get ">"
String 1: 0.455

Any help is appreciated, I thank you so much in advance.
Thanks



As snk_kid suggests, try boost::spirit.


void getTag(char const *begin, char const *end);

std::string objectname;

boost::spirit::rule<phrase_scanner_t> tag, object;

tag = uint_p >> '<' >> real_p >> ',' >> real_p >> '>';
object = (+alnum_p)[assign_a(objectname)] >> '{' >> (*tag[&getTag]) >> '}';



... and so on...

That's just an example to show how easy it is to create a parser w/boost::spirit.

Share this post


Link to post
Share on other sites
I've just popped back to the house and have had a bit of time to look at this more carefully, and to test it. It can be simplified further. Here's the code:


// Check these stdlibs.
#include <fstream>
#include <iostream>
#include <limits>
#include <vector>

int main (int argc, const char * argv[])
{

// Ref characters.
std::string digitch_ = "0123456789";

std::ifstream stream;
std::string my_file = "my_file.txt";
stream.open(my_file.c_str());
char ch;
float flt;
std::vector<float> vFloat;

// Need to loop here to end of file.
while (stream.get(ch))
{
if (digitch_.find( ch ) != std::string::npos)
// Read and parse each line beginning with a digit.
{
stream.ignore(std::numeric_limits<std::streamsize>::max(),'<'); // Ignores to '<'

stream >> flt; // Stream in x.
vFloat.push_back(flt); // Adds to vFloat.

stream.ignore(std::numeric_limits<std::streamsize>::max(),','); // Ignore that delimiter.

stream >> flt; // Stream in y.
vFloat.push_back(flt); // Adds to vFloat.

stream.ignore(std::numeric_limits<std::streamsize>::max(),'\n'); // Ignores to end of line.
}
else
// Ignore everything else.
{
stream.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
}
}

unsigned int i = 0;
while (i < vFloat.size())
{
std::cout << vFloat << "\t" << vFloat[i + 1] << std::endl;
i += 2;
}
return EXIT_SUCCESS;
}






Here's the input:


Object1{
0<0.05,0.455>
1<0.1,0.455>
2<0.15,0.455>
3<0.2,0.455>
4<0.25,0.455>
5<0.3,0.455>
6<0.35,0.455>
7<0.4,0.455>
Object1}





And heres the output:


0.05 0.455
0.1 0.455
0.15 0.455
0.2 0.455
0.25 0.455
0.3 0.455
0.35 0.455
0.4 0.455





[Edited by - random_thinker on August 28, 2005 2:33:14 PM]

Share this post


Link to post
Share on other sites
Oh man you guys are wonderful, thank you everybody.
random_thinker your code work perfectly, I love it, thank you so much.
I looked at TinyXML and it looks good and I am planning to change everything to XML in future but not now.

Thank you again.

Share this post


Link to post
Share on other sites
If you liked that code, this one will knock your socks off! This will parse each code section if you just give the parser a 'hint' as to what section to look for (i.e. "Tex" for "Texture1" section, "Obj" for "Object1" section, etc. It also should be much more efficient in searching. Here's the code:


// Check these stdlibs.
#include <fstream>
#include <iostream>
#include <limits>
#include <vector>

void parse(std::ifstream & stream, std::vector<float> & vec)
{
char ch;
float flt;

while (stream.get(ch))
{
if (ch == '<')
{
stream >> flt;
vec.push_back(flt);
}

else if (ch == ',')
{
stream >> flt;
vec.push_back(flt);
}

else if (ch == '>')
{
stream.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
}

else if (ch == '}')
{
return;
}
}
}

int main (int argc, const char * argv[])
{
unsigned int i;
std::ifstream stream;
std::string my_file = "my_file.txt", data_set;
std::vector<float> vObject, vTexture;

// Open stream.
stream.open(my_file.c_str());

while (!stream.fail())
{
// Search for next data_set
stream >> data_set;

// Start looking for Objects.
if (data_set.find( "Obj" ) != std::string::npos)
{
parse(stream,vObject);
}

// Start looking for Textures.
else if (data_set.find( "Tex" ) != std::string::npos)
{
parse(stream,vTexture);
}
}

// Print it out.
std::cout << "Object Data" << std::endl;
for (i = 0; i < vObject.size();)
{
std::cout << vObject << "\t" << vObject[i + 1] << std::endl;
i += 2;
}

std::cout << "\nTexture Data" << std::endl;
for (i = 0; i < vTexture.size();)
{
std::cout << vTexture << "\t" << vTexture[i + 1] << std::endl;
i += 2;
}

return EXIT_SUCCESS;
}




Here's the file data:


Object1{
0<0.05,0.455>
1<0.1,0.455>
2<0.15,0.455>
3<0.2,0.455>
4<0.25,0.455>
5<0.3,0.455>
6<0.35,0.455>
7<0.4,0.455>
Object1}

Texture1{
0<0.05,0.400>
1<0.1,0.400>
2<0.15,0.400>
3<0.2,0.400>
4<0.25,0.400>
5<0.3,0.400>
6<0.35,0.400>
7<0.4,0.400>
Texture1}




Here's the output:


Object Data
0.05 0.455
0.1 0.455
0.15 0.455
0.2 0.455
0.25 0.455
0.3 0.455
0.35 0.455
0.4 0.455

Texture Data
0.05 0.4
0.1 0.4
0.15 0.4
0.2 0.4
0.25 0.4
0.3 0.4
0.35 0.4
0.4 0.4




It should give you a very simple method of complete parsing any file format like the one you've shown.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!