Reading a text file and using delimiters

closed account (LNhCLyTq)
I have a text file which has the following format:
"coffee [drink]
Black coffee; Cappuccino;
Latte;

lasagne [food]
Chicken; Beef;"

The format is name [type] \n examples and each example is separated with a semi-colon. I would like to read these from a text file and put them in three attributes called name, type and example. However, I have the following query:

- How do I split line 1 (e.g. coffee [drink]' to put coffee in attribute name and drink in attribute type
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
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;


// Faked input file; remove after testing
istringstream in(
"coffee [drink]             \n"
"Black coffee; Cappuccino;  \n"
"Latte;                     \n"
"                           \n"
"lasagne [food]             \n"
"Chicken; Beef;             \n"
);


struct Item
{
   string name;
   string type;
   vector<string> examples;

   void print()
   {
      cout << "Name: " << name << '\n'
           << "Type: " << type << '\n'
           << "Examples: ";
      for ( const string &s : examples ) cout << s << ' ';
      cout << "\n\n";
   }
};


//==========================================================


string trim( const string &s, const string &junk = " " )
{
   int i = s.find_first_not_of( junk );
   if ( i == string::npos ) return "";

   int j = s.find_last_not_of( junk );
   return s.substr( i, j - i + 1 );
}


//==========================================================


void split( const string &line, string &name, string &type )
{
   int p = line.find( '[' ), q = line.find( ']' );
   name = trim( line.substr( 0, p ) );
   type = trim( line.substr( p + 1, q - p - 1 ) );
}


//==========================================================


int main()
{
// ifstream in( "input.txt" );
   vector<Item> menu;

   Item item;
   for ( string line; getline( in, line ); )
   {
       if ( line.find( '[' ) != string::npos )
       {
          // Put any previous item in the menu
          if ( item.name != "" ) 
          {
             menu.push_back( item );
             item.name = "";
          }

          // Start new item
          item.examples.clear();
          split( line, item.name, item.type );
       }
       else if ( !line.empty() )
       {
          // Add to current examples
          stringstream ss( line ); 
          for ( string eg; getline( ss, eg, ';' ); ) 
          {
             eg = trim( eg );
             if ( !eg.empty() ) item.examples.push_back( eg );
          }
       }
   }
   if ( item.name != "" ) menu.push_back( item );

   for ( Item &item : menu ) item.print();
}


Name: coffee
Type: drink
Examples: Black coffee Cappuccino Latte 

Name: lasagne
Type: food
Examples: Chicken Beef
Hello Ellen2001,

Since you are new here. Unless you want answers beyond what you have learned yet it helps to mention what you do know and to post any code you have so others can know what you are trying to do.

Since the program is required to read it helps to include the input file or at least a good sample to work with. This way everyone will have the same information to work with.

lastchance has a very nice program, but do you understand all of it? Or do you need something that is less advanced? Something to think about when you post a question here.

This will help when it does come time to post code:

PLEASE ALWAYS USE CODE TAGS (the <> formatting button), to the right of this box, when posting code.

Along with the proper indenting it makes it easier to read your code and also easier to respond to your post.

http://www.cplusplus.com/articles/jEywvCM9/
http://www.cplusplus.com/articles/z13hAqkS/

Hint: You can edit your post, highlight your code and press the <> formatting button. This will not automatically indent your code. That part is up to you.

You can use the preview button at the bottom to see how it looks.

I found the second link to be the most help.



If you have your answer that is good. Otherwise keep this in mind for the future.

Andy
closed account (LNhCLyTq)
@lastchance
Hi, I tried your code but my problem is that the struct 'Item' has to be a class with its attributes private with public getters and setters, how do I modify the code to do that? I tried but unfortunately failed.

@Andy
Thank you, I will keep that in mind
Ellen2001 wrote:
my problem is that the struct 'Item' has to be a class with its attributes private with public getters and setters, how do I modify the code to do that?


Minimal version below. name and type are set by the constructor (which I think is natural), but you could add separate setters for them if you want. Examples are added by member function addExample().

I dislike excessive use of the qualifier 'const' or passing short strings by reference, but feel free to add where necessary.

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
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;


// Faked input file for testing
istringstream in(
"coffee [drink]             \n"
"Black coffee; Cappuccino;  \n"
"Latte;                     \n"
"                           \n"
"lasagne [food]             \n"
"Chicken; Beef;             \n"
);


//==========================================================


class Item
{
// private members (by default)
   string name;
   string type;
   vector<string> examples;

public:                      // public interface
   Item( string n = "", string t = "" ) : name( n ), type ( t ) {}   // constructor

   string getName(){ return name; }
   string getType(){ return type; }

   void addExample( string eg ){ examples.push_back( eg ); }

   void clear()
   {
      name = type = "";
      examples.clear();
   }

   void print()
   {
      cout << "Name: " << name << '\n'
           << "Type: " << type << '\n'
           << "Examples: ";
      for ( string s : examples ) cout << s << "  ";
      cout << "\n\n";
   }
};


//==========================================================


string trim( const string &s, const string &junk = " " )        // strips leading/trailing blanks etc.
{
   int i = s.find_first_not_of( junk );
   if ( i == string::npos ) return "";

   int j = s.find_last_not_of( junk );
   return s.substr( i, j - i + 1 );
}


//==========================================================


void splitByBracket( const string &line, string &name, string &type )
{
   int p = line.find( '[' ), q = line.find( ']' );
   name = trim( line.substr( 0, p ) );
   type = trim( line.substr( p + 1, q - p - 1 ) );
}


//==========================================================


int main()
{
// ifstream in( "input.txt" );    // uncomment (and remove the stringstream above) later
   vector<Item> menu;

   Item item;
   for ( string line; getline( in, line ); )               // Read line by line
   {
       if ( line.find( '[' ) != string::npos )             // If it contains '[' start a new item
       {
          // Put any previous item in the menu first and reset item to empty
          if ( item.getName() != "" )
          {
             menu.push_back( item );
             item.clear();
          }

          // Start new item
          string name, type;
          splitByBracket( line, name, type );
          item = Item( name, type );
       }
       else if ( line != "" )                              // Otherwise, add to the example list
       {
          stringstream ss( line ); 
          for ( string eg; getline( ss, eg, ';' ); ) 
          {
             eg = trim( eg );
             if ( eg != "" ) item.addExample( eg );
          }
       }
   }
   if ( item.getName() != "" ) menu.push_back( item );     // Deal with last item

   // Let's see what we've got
   for ( Item &item : menu ) item.print();
}


Name: coffee
Type: drink
Examples: Black coffee  Cappuccino  Latte  

Name: lasagne
Type: food
Examples: Chicken  Beef  
Topic archived. No new replies allowed.