Problems parsing a file

E

Eric Lilja

Hello, I'm creating a small utility for an online game. It involves
parsing a text file of "tradesskill recipes" and inserting these
recipes in a gui tree widget (similar to gui file browsers if you know
what I mean).
Here's an example of a recipe as it appears in the text file:
* Cashew Pie (lvl 39, 5h 3 min, + max power)
- Candied Cashew (level 30)
-- Cashew
-- Refined Honey (level 30)
--- Raw Honey
--- Liquid
- Dough
- Refined Honey (level 30)
-- Raw Honey
-- Liquid

* denotes new recipe (a new root node in the tree)
-/--/--- denotes the depth of the child node.
One node per line.

The gui code is out of scope for the ng, but the parser is written in
standard C++, and I'm having some problems with it. The code:
#include <cassert>
#include <cctype>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <stdexcept>
#include <string>

using std::cerr;
using std::cout;
using std::endl;
using std::ifstream;
using std::isspace;
using std::runtime_error;
using std::string;

enum depth_t { NO_DEPTH = 0, FIRST, SECOND, THIRD };

static depth_t get_depth(const string &);

int
main()
{
ifstream food_recipes_file("recipes_food.txt");

if(!food_recipes_file)
{
cerr << "Failed to open food recipe file." << endl;

return EXIT_FAILURE;
}

string line;
string recipe_root_node;
depth_t previous_depth = NO_DEPTH;

while(getline(food_recipes_file, line))
{
if(line[0] == '*')
{
assert(line[1] == ' ');

recipe_root_node = line.substr(2, line.length());
cout << "Inserting new recipe " << line << endl;

previous_depth = NO_DEPTH;
}
else if(isspace(line[0]))
; /* Simply skip lines beginning with a blank. */
else /* We're not dealing with a new recipe */
{
assert(line[0] == '-');

depth_t depth = get_depth(line);

cout << line << " at depth " << endl;
}
}

food_recipes_file.close();

return EXIT_SUCCESS;
}

/* get_depth() assumes the first char in line is a - */
static depth_t
get_depth(const string& line)
{
if(line[1] == ' ')
return FIRST;

/* If the second char is not a ' ', it must be a '-'. */
assert(line[1] == '-');

if(line[2] == ' ')
return SECOND;

/* If the third char is not a ' ', it must be a '-'. */
assert(line[2] == '-');

if(line[3] == ' ')
return THIRD;

throw runtime_error("Couldn't identify depth!");
}

This compiles without warning on my compiler (with warning level set to
max, all extension turned off), but the output is really messed up:
$ ./create_tree.exe
Inserting new recipe * Cashew Pie (lvl 39, 5h 3 min, + max power)
at depth Cashew (level 30)
at depth
at depth Honey (level 30)
at depth ney
at depth
at depth
at depth Honey (level 30)
at depth ey
at depth

Any obvious errors?

Thanks for any replies!

/ E
 
E

Eric Lilja

Eric Lilja wrote:
[snip]

Well, turns out the recipe file was in dos style line breaks and the
executable was expecting unix style line breaks. I converted the text
file to unix style line breaks and everything works. But I might be
back with further questions. =)

/ E
 
M

Mike Wahler

Eric Lilja said:
Hello, I'm creating a small utility for an online game. It involves
parsing a text file of "tradesskill recipes" and inserting these
recipes in a gui tree widget (similar to gui file browsers if you know
what I mean).
Here's an example of a recipe as it appears in the text file:
* Cashew Pie (lvl 39, 5h 3 min, + max power)
- Candied Cashew (level 30)
-- Cashew
-- Refined Honey (level 30)
--- Raw Honey
--- Liquid
- Dough
- Refined Honey (level 30)
-- Raw Honey
-- Liquid

* denotes new recipe (a new root node in the tree)
-/--/--- denotes the depth of the child node.
One node per line.

The gui code is out of scope for the ng, but the parser is written in
standard C++, and I'm having some problems with it. The code:
#include <cassert>
#include <cctype>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <stdexcept>
#include <string>

using std::cerr;
using std::cout;
using std::endl;
using std::ifstream;
using std::isspace;
using std::runtime_error;
using std::string;

enum depth_t { NO_DEPTH = 0, FIRST, SECOND, THIRD };

static depth_t get_depth(const string &);

int
main()
{
ifstream food_recipes_file("recipes_food.txt");

if(!food_recipes_file)
{
cerr << "Failed to open food recipe file." << endl;

return EXIT_FAILURE;
}

string line;
string recipe_root_node;
depth_t previous_depth = NO_DEPTH;

while(getline(food_recipes_file, line))
{
if(line[0] == '*')
{
assert(line[1] == ' ');

recipe_root_node = line.substr(2, line.length());
cout << "Inserting new recipe " << line << endl;

previous_depth = NO_DEPTH;
}
else if(isspace(line[0]))
; /* Simply skip lines beginning with a blank. */
else /* We're not dealing with a new recipe */
{
assert(line[0] == '-');

depth_t depth = get_depth(line);

cout << line << " at depth " << endl;
}
}

food_recipes_file.close();

return EXIT_SUCCESS;
}

/* get_depth() assumes the first char in line is a - */
static depth_t
get_depth(const string& line)
{
if(line[1] == ' ')
return FIRST;

/* If the second char is not a ' ', it must be a '-'. */
assert(line[1] == '-');

if(line[2] == ' ')
return SECOND;

/* If the third char is not a ' ', it must be a '-'. */
assert(line[2] == '-');

if(line[3] == ' ')
return THIRD;

throw runtime_error("Couldn't identify depth!");
}

This compiles without warning on my compiler (with warning level set to
max, all extension turned off), but the output is really messed up:
$ ./create_tree.exe
Inserting new recipe * Cashew Pie (lvl 39, 5h 3 min, + max power)
at depth Cashew (level 30)
at depth
at depth Honey (level 30)
at depth ney
at depth
at depth
at depth Honey (level 30)
at depth ey
at depth

Any obvious errors?

Thanks for any replies!

After fixing the one error that caused your code to
fail to compile:

using std::getline;

and creating an input file with your sample data,
it compiled and linked OK for me (MSVC 6.0 SP6),
and gave the following output:

Inserting new recipe * Cashew Pie (lvl 39, 5h 3 min, + max power)
- Candied Cashew (level 30) at depth
-- Cashew at depth
-- Refined Honey (level 30) at depth
--- Raw Honey at depth
--- Liquid at depth
- Dough at depth
- Refined Honey (level 30) at depth
-- Raw Honey at depth
-- Liquid at depth


(I don't know if it's part of what you called 'messed up',
but the reason there's nothing after 'at depth' is because
the code makes no attempt to output that value.)

-Mike
 
E

Eric Lilja

Mike said:
Eric Lilja said:
Hello, I'm creating a small utility for an online game. It involves
parsing a text file of "tradesskill recipes" and inserting these
recipes in a gui tree widget (similar to gui file browsers if you know
what I mean).
Here's an example of a recipe as it appears in the text file:
* Cashew Pie (lvl 39, 5h 3 min, + max power)
- Candied Cashew (level 30)
-- Cashew
-- Refined Honey (level 30)
--- Raw Honey
--- Liquid
- Dough
- Refined Honey (level 30)
-- Raw Honey
-- Liquid

* denotes new recipe (a new root node in the tree)
-/--/--- denotes the depth of the child node.
One node per line.

The gui code is out of scope for the ng, but the parser is written in
standard C++, and I'm having some problems with it. The code:
#include <cassert>
#include <cctype>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <stdexcept>
#include <string>

using std::cerr;
using std::cout;
using std::endl;
using std::ifstream;
using std::isspace;
using std::runtime_error;
using std::string;

enum depth_t { NO_DEPTH = 0, FIRST, SECOND, THIRD };

static depth_t get_depth(const string &);

int
main()
{
ifstream food_recipes_file("recipes_food.txt");

if(!food_recipes_file)
{
cerr << "Failed to open food recipe file." << endl;

return EXIT_FAILURE;
}

string line;
string recipe_root_node;
depth_t previous_depth = NO_DEPTH;

while(getline(food_recipes_file, line))
{
if(line[0] == '*')
{
assert(line[1] == ' ');

recipe_root_node = line.substr(2, line.length());
cout << "Inserting new recipe " << line << endl;

previous_depth = NO_DEPTH;
}
else if(isspace(line[0]))
; /* Simply skip lines beginning with a blank. */
else /* We're not dealing with a new recipe */
{
assert(line[0] == '-');

depth_t depth = get_depth(line);

cout << line << " at depth " << endl;
}
}

food_recipes_file.close();

return EXIT_SUCCESS;
}

/* get_depth() assumes the first char in line is a - */
static depth_t
get_depth(const string& line)
{
if(line[1] == ' ')
return FIRST;

/* If the second char is not a ' ', it must be a '-'. */
assert(line[1] == '-');

if(line[2] == ' ')
return SECOND;

/* If the third char is not a ' ', it must be a '-'. */
assert(line[2] == '-');

if(line[3] == ' ')
return THIRD;

throw runtime_error("Couldn't identify depth!");
}

This compiles without warning on my compiler (with warning level set to
max, all extension turned off), but the output is really messed up:
$ ./create_tree.exe
Inserting new recipe * Cashew Pie (lvl 39, 5h 3 min, + max power)
at depth Cashew (level 30)
at depth
at depth Honey (level 30)
at depth ney
at depth
at depth
at depth Honey (level 30)
at depth ey
at depth

Any obvious errors?

Thanks for any replies!

After fixing the one error that caused your code to
fail to compile:

using std::getline;

I was under the impression that I didn't have to qualify getline() in
this case because of Koenig lookup?
and creating an input file with your sample data,
it compiled and linked OK for me (MSVC 6.0 SP6),
and gave the following output:

Inserting new recipe * Cashew Pie (lvl 39, 5h 3 min, + max power)
- Candied Cashew (level 30) at depth
-- Cashew at depth
-- Refined Honey (level 30) at depth
--- Raw Honey at depth
--- Liquid at depth
- Dough at depth
- Refined Honey (level 30) at depth
-- Raw Honey at depth
-- Liquid at depth


(I don't know if it's part of what you called 'messed up',
but the reason there's nothing after 'at depth' is because
the code makes no attempt to output that value.)

Thanks for taking the time to test this, Mike, but did you read my
reply to myself? It was a silly line-break mess-up. =( I removed the
output of the depth variable when trying to track down the error.

/ E
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,071
Latest member
MetabolicSolutionsKeto

Latest Threads

Top