Can't read in data separated by delimiters

Feb 1, 2020 at 10:54pm
I'm working on a project for my cs162 class and am having some trouble. For part of my project I have a .txt file with a list of song attributes seperated by delimiters that I need to read into an array of structs(.txt file elements have to be seperated by delimiters).

It reads in the struct's Title, Artist, and Album fine but it wont read in the Min or Sec. I do eventually need to loop this to read in every song. I spent 5 hours trying to troubleshoot this yesterday and am at my wit's end. I would greatly appreciate any help.

//file below////////////////////////////////////

#include <iostream>
#include <cstring>
#include <fstream>

using namespace std;

const int MAX_CHAR=101;

struct Song
{
char Title[MAX_CHAR];
char Artist[MAX_CHAR];
char Album[MAX_CHAR];
int Min;
int Sec;
};

int main()

{

Song song[i];

ifstream in;
in.open("roster.txt");
if(!in) return(1);

in.get(song[i].Title, MAX_CHAR, ';');
in.ignore();
in.get(song[i].Artist, MAX_CHAR, ';');
in.ignore();
in.get(song[i].Album, MAX_CHAR, ';');
in>>song[i].Min;
in.ignore(MAX_CHAR, ';');
in>>song[i].Sec;
in.ignore(MAX_CHAR, '\n');



cout<<song[i].Title<<endl;

cout<<song[i].Artist<<endl;
cout<<song[i].Album<<endl;
cout<<song[i].Min<<endl;
cout<<song[i].Sec<<endl;

in.close();

return 0;
}
//////////////////////////////////////////////////////////////////////

//roster.txt below////////////////////////////////////////////////////

Break;Three Days Grace;Life Starts Now;3;13
Joker And The Thief;Wolfmother;Wolfemother;4;40
Satellite;Rise Against;Endgame;3;58
Come with Me Now;Kongos;Lunatic;3;31
//////////////////////////////////////////////////////////////////////

//Output of code below///////////////////////

Break
Three Days Grace
Life Starts Now
4
32766
Feb 2, 2020 at 12:23am
closed account (1Ck93TCk)
Hi theleonicking,

It looks like we're working on the same assignment! lol. I did a quick side-by-side and there are a couple of things different.

HUGE disclaimer. I am a beginner and should not be trusted. I just think I might have some insight since I'm working on the same program.

First, instead of in.get, I used infile.get. Because we're reading from a file, right?
Second, I'm not sure you need all of those ignore statements. I just used it once, at the end of the input statements.
Third, what I did was use cin.get() in all of the places that you put cin.ignore(). This throws out the semicolon delimiter (which I think you were trying to do with ignore?).

Hope that helps!

And if anything I'm saying is bad info I hope someone will speak up so I can learn.

Good luck!
jmb
Last edited on Feb 2, 2020 at 12:25am
Feb 2, 2020 at 1:03am
Thanks and the the changes don't seem to be working sadly. If yours is working right, could you paste your version of this part so I can see what's going on?

GL to you too!
Feb 2, 2020 at 1:37am
Try this as a framework to build on. There are plenty of other ways to do this but seeing that you are using C-strings this way using strtok() to parse each line is OK.

See the strtok() reference and sample program on this site. Try the sample first :)
http://www.cplusplus.com/reference/cstring/strtok/?kw=strtok

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
#include <iostream>
#include <cstring>
#include <fstream>

using namespace std;

const int MAX_CHAR = 200;

struct Song
{
    char Title[MAX_CHAR];
    char Artist[MAX_CHAR];
    char Album[MAX_CHAR];
    int Min;
    int Sec;
};

const int ALBUM_SIZE = 100;

int main()

{
    Song song[ALBUM_SIZE];
    
    char buffer[MAX_CHAR];
    
    ifstream in;
    in.open("roster.txt");
    if(!in)
    {
        return(1);
    }
    
    int song_no = 0; // BECOMES USEFUL LATER ON
    while( in.getline(buffer, MAX_CHAR) )
    {
        cout << song_no << ' ' << buffer << '\n';
        // USE strtok() FUNCTION HERE AND AS EACH TOKEN ROLLS OUT
//        song[song_no].Title = ...
//        etc
        
        song_no++;
    }
    
    in.close();
    
    return 0;
}
Last edited on Feb 2, 2020 at 1:38am
Feb 2, 2020 at 1:43am
PS The includes in the sample are a bit out of date so this works just as well.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/* strtok example */
#include <iostream>
#include <cstring>

int main ()
{
  char str[] ="- This, a sample string.";
  char * pch;
  printf ("Splitting string \"%s\" into tokens:\n",str);
  pch = strtok (str," ,.-");
  while (pch != NULL)
  {
    printf ("%s\n",pch);
    pch = strtok (NULL, " ,.-");
  }
  return 0;
}
Feb 2, 2020 at 2:26am
Just to give you an idea...

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
#include <iostream>
#include <string>
#include <ios> // for streamsize
#include <limits> // for include numeric_limits.
#include <fstream>


struct Song
{
	std::string Title;
	std::string Artist;
	std::string Album;
	int Min;
	int Sec;
};

int main()

{
	const int totalOfElemFile = 4;
	Song song[totalOfElemFile];

	std::ifstream in;
	in.open("roster.txt");
	if (!in) return(1);

	for (int count = 0; count < totalOfElemFile; count++)
	{
		std::getline(in, song[count].Title, ';');
		std::getline(in, song[count].Artist, ';');
		std::getline(in, song[count].Album, ';');
		in >> song[count].Min;
		in.ignore(std::numeric_limits<std::streamsize>::max(), ';');
		in >> song[count].Sec;

	}

	for (int count = 0; count < totalOfElemFile; count++)
	{
		std::cout << song[count].Title << std::endl;
		std::cout << song[count].Artist << std::endl;
		std::cout << song[count].Album << std::endl;
		std::cout << song[count].Min << std::endl;
		std::cout << song[count].Sec << std::endl;
	}

	in.close();

	return 0;
}


Output...

Break
Three Days Grace
Life Starts Now
3
13

Joker And The Thief
Wolfmother
Wolfemother
4
40

Satellite
Rise Against
Endgame
3
58

Come with Me Now
Kongos
Lunatic
3
31
Feb 2, 2020 at 2:56am
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
#include <iostream>
#include <cstring>
#include <fstream>

using namespace std;

const int MAX_CHAR = 200;

struct Song
{
    char Title[MAX_CHAR];
    char Artist[MAX_CHAR];
    char Album[MAX_CHAR];
    int Min;
    int Sec;
};

const int ALBUM_SIZE = 100;

int main()

{
    Song song[ALBUM_SIZE];
    
    char buffer[MAX_CHAR];
    
    ifstream in;
    in.open("roster.txt");
    if(!in)
    {
        return(1);
    }
    
    int song_no = 0; // BECOMES USEFUL LATER ON
    char *pch;
    
    while( in.getline(buffer, MAX_CHAR) )
    {
        cout << song_no << ' ' << buffer << '\n';
        
        char temp[5][MAX_CHAR];// HOLDS THE TOKENS
        
        // TOKENIZE
        int counter = 0;
        
        pch = strtok (buffer,";");
        while (pch != nullptr)
        {
            strcpy(temp[counter], pch);
            cout << counter << ' ' << temp[counter] << '\n';
            
            pch = strtok (nullptr, ";");
            counter++;
        }
        
        strcpy(song[song_no].Title, temp[0]);
        strcpy(song[song_no].Album, temp[1]);
        strcpy(song[song_no].Artist, temp[2]);
        
        // NOW  CONVERT TO INTEGERS IF REQUIRED
        song[song_no].Min = std::atoi(temp[3]);
        song[song_no].Sec = std::atoi(temp[4]);

        song_no++;
    }
    in.close();
    
    for(int i = 0; i < song_no; i++)
    {
        if( strcmp(song[i].Album, "Wolfmother") )
            cout << "****************** Bingo\n";
        
        cout
        << "\""
        << song[i].Album << "\" by "
        << song[i].Artist
        << " Length: "
        << song[i].Min << ":"
        << song[i].Sec
        
        << '\n';
    }
    
    return 0;
}


0 Break;Three Days Grace;Life Starts Now;3;13
0 Break
1 Three Days Grace
2 Life Starts Now
3 3
4 13
1 Joker And The Thief;Wolfmother;Wolfemother;4;40
0 Joker And The Thief
1 Wolfmother
2 Wolfemother
3 4
4 40
2 Satellite;Rise Against;Endgame;3;58
0 Satellite
1 Rise Against
2 Endgame
3 3
4 58
3 Come with Me Now;Kongos;Lunatic;3;31
0 Come with Me Now
1 Kongos
2 Lunatic
3 3
4 31
****************** Bingo
"Three Days Grace" by Life Starts Now Length: 3:13
"Wolfmother" by Wolfemother Length: 4:40
****************** Bingo
"Rise Against" by Endgame Length: 3:58
****************** Bingo
"Kongos" by Lunatic Length: 3:31
Program ended with exit code: 0


EDIT: for strcmp()
Last edited on Feb 3, 2020 at 1:25am
Feb 2, 2020 at 3:37am
againtry , Nice!
Feb 2, 2020 at 4:12am
Thanks, yours too with another approach.

I would have helped the other guy, but you saw the result.
Feb 2, 2020 at 5:34am
Thanks so much you guys! Now all I have left to do is figure out my search functions.
Feb 2, 2020 at 5:44am
strcmp() is a C function that won't go astray.

Hint: Once you have a match the key result is the index number of the song, and don't go beyond the counted number of songs.
Feb 3, 2020 at 12:30am
Thanks, I've been fooling around with strcmp but I can't seem to convert an inputed name or my song[i].Artist into a char a[] value like the syntax for it shows.
Feb 3, 2020 at 1:26am
See above for strcmp() EDIT.

Next step is to store the cin value in a buffer to automate the comparison
Feb 3, 2020 at 1:43am
Thanks and I finally figured it out. I had to use strcpy to convert. Its all working now except for the loop. I tried nesting a do..while loop inside a for loop so that i would increment and the strcmp value would stop at the correct value but it just loops infinitely.

void searchartist(int &listsize, int &i, Song song[])
{
listsize=i;
i=0;
cout<<"Please enter the name of the song's artist: ";

char artist[MAX_CHAR];
cin >> artist;
cin.ignore(MAX_CHAR, '\n');
char *a1=artist;
strcpy(a1, artist);
cout<<a1<<endl<<endl;;
int Compare;
char *a2=song[i].Artist;
strcpy(a2, song[i].Artist);
strcmp(a1, a2);

for(i=0;i<listsize;i++)
{
do
{
a2=song[i].Artist;
Compare=strcmp(a1,a2);
cout<<a1<<" : "<<a2<<" : "<<Compare<<endl;
}while(Compare!=0);
}
cout<<song[i].Title<<endl;
Feb 3, 2020 at 1:52am
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
    cout << "Enter Artist to search for? ";
    cin.getline(buffer, MAX_CHAR);
    cout << "Searching for: " << buffer << '\n';
    
    for(int i = 0; i < song_no; i++)
    {
        if( strcmp(buffer, song[i].Artist) == 0 )
        {
            cout << "****************** Bingo\n";
            
            cout
            << "\""
            << song[i].Album << "\" by "
            << song[i].Artist
            << " Length: "
            << song[i].Min << ":"
            << song[i].Sec
            
            
            << '\n';
        }
    }


Topic archived. No new replies allowed.