Thread: i need help with string streams

  1. #1
    Registered User
    Join Date
    Apr 2005
    Posts
    76

    i need help with string streams

    I'm still putting finshing touches on this Phonebook Entry program I am working on. I am using a data file that will keep the data in a formatted style so that the user can look at the .txt file and be able to find information easily without having to load the program every time. So, essentially, I am outputing to a file in a formated form>>>
    Code:
    Name:                  John Doe
    Home Phone Number:     333-3333
    Cell Phone Number:     444-4444
    Address:               123 Hello Dr.
    Now when the program opens a file, it uses getline for every line and sets each one to a separate string. Everything is fine, except that I need to get the actual data out of the string.
    Code:
    Ex.
    
    (GET LINE FROM FILE. SET TO STRING)
    
    Name:                  John Doe << this is the string
    
    I want to get data out of the string.
    
    John Doe << i want this data out of the string above.
    I realize i need to use string streams, but I don't know how to skip the Name: and the whitespace to get to John Doe.

    Here is my getline function, and my attempt with string streams.

    Code:
    /*******************************/
    /**** Phonebook::GetEntries ****/
    /*******************************/
    void Phonebook::GetEntries(fstream &fFile)
    {
         stringstream s;
         char test1;
         Entry temp;
         
         if(get(fFile,test1)==NULL)
         {
                        return;
         }
         else
         {
             while(getline(fFile,temp.name))
             {
                       getline(fFile,temp.cnumber);
                       getline(fFile,temp.hnumber);
                       getline(fFile,temp.address);
                       
                       s.str(temp.name);
                       s >> "Name:\t\t\t" >> temp.name;
                       s.str(temp.cnumber);
                       s >> "Cell Phone Number:\t" >> temp.cnumber;
                       s.str(temp.hnumber);
                       s >> "Cell Phone Number:\t" >> temp.hnumber;
                       s.str(temp.address);
                       s >> "Address:\t\t">> temp.address;
                       
                       vEntries.push_back(temp);
             }
         }
    }

  2. #2
    (?<!re)tired Mario F.'s Avatar
    Join Date
    May 2006
    Location
    Ireland
    Posts
    8,446

    Post

    If that file is not tampered with you can interact across the array in a fashion similar to the following pseudo code.

    Code:
    For each getline() {
    counter = 0;
    for (end of array to begin of array) {
         if (position is whitespace) counter++;
         else counter = 0;
    
         if (counter == 2)  { //you just found 2 whitespaces on a row
               pos = current_array_position + 2;
               while (pos is not end of array) yourstring += array[pos++];
         }
    }
    I'm myself a newcommer to C++. So sorry for the pseudo code. I believe your problem is more one of logic than one of syntax

  3. #3
    Registered User
    Join Date
    Apr 2003
    Posts
    2,663
    I realize i need to use string streams, but I don't know how to skip the Name: and the whitespace to get to John Doe.
    Pretend that your stringstream is a file. Reading from a file can be done with the >> operator, e.g.
    Code:
    inFile>>myStr;
    It so happens, the >> operator is programmed to skip any leading whitespace and to stop reading when it encounters any trailing whitespace. So, you can do this:
    Code:
    inStr>>heading;
    inStr>>firstName;
    inStr>>lastName;
    or more succinctly:
    Code:
    inStr>>heading>>firstName>>lastName;
    Last edited by 7stud; 05-26-2006 at 03:17 PM.

  4. #4
    Registered User
    Join Date
    Apr 2005
    Posts
    76
    ok so this is my new code...
    Code:
    /*******************************/
    /**** Phonebook::GetEntries ****/
    /*******************************/
    void Phonebook::GetEntries(fstream &fFile)
    {
         string heading;
         string first,last;
         string cnumber;
         string hnumber;
         string address;
    
         stringstream s;
         Entry temp;
         
         if(fFile.peek()=='\0')
         {
                        return;
         }
         else
         {
             while(getline(fFile,temp.name))
             {
                       getline(fFile,temp.cnumber);
                       getline(fFile,temp.hnumber);
                       getline(fFile,temp.address);
                       
                       s.str(temp.name);
                       s >> heading >> first >> " " >> last;
                       temp.name=s;
                       s.str(temp.cnumber);
                       s >> heading >> cnumber;
                       temp.cnumber=s;
                       s.str(temp.hnumber);
                       s >> heading >> hnumber;
                       temp.hnumber=s;
                       s.str(temp.address);
                       s >> heading >> address;
                       temp.address=s;
                       
                       vEntries.push_back(temp);
             }
         }
    }
    now i need to take the edited string stream and turn it back into a string... what i have done above doesnt work cause i know you probably can't compare a stream with a string....so yea... thats where i am at

  5. #5
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,613
    Well technically all those "temp" variable would be strings. Use those.

  6. #6
    Registered User
    Join Date
    Apr 2005
    Posts
    76
    NEW CODE
    Code:
    /*******************************/
    /**** Phonebook::GetEntries ****/
    /*******************************/
    void Phonebook::GetEntries(fstream &fFile)
    {
         string heading;
         string first,last;
    
         stringstream s;
         Entry temp;
         
         if(fFile.peek()=='\0')
         {
                        return;
         }
         else
         {
             while(getline(fFile,temp.name))
             {
                       getline(fFile,temp.cnumber);
                       getline(fFile,temp.hnumber);
                       getline(fFile,temp.address);
                       
                       s.str(temp.name);
                       temp.name.clear();
                       s >> heading >> first >> last;
                       temp.name=first+" "+last;
                       s.str("");
                       
                       s.str(temp.cnumber);
                       temp.cnumber.clear();
                       s >> heading >> temp.cnumber;
                       s.str("");
                       
                       s.str(temp.hnumber);
                       temp.hnumber.clear();
                       s >> heading >> temp.hnumber;
                       s.str("");
                       
                       s.str(temp.address);
                       temp.address.clear();
                       s >> heading >> temp.address;
                       s.str("");
                       
                       vEntries.push_back(temp);
             }
         }
    }
    your right... but i have to clear the string for some reason for it to work...and now its displaying the name but its not getting the cell number, home number, and address... so the stream works once...but it should work multiple times because i clear it after i am done each time...

    Code:
    /***********************************/
    /**** Phonebook::DisplayEntries ****/
    /***********************************/
    void Phonebook::DisplayEntries()
    {
         if(vEntries.size()==0)
         {
                               cout<<"\n\t\t\t\t  >FILE EMPTY<";
                               cout<<endl<<endl;
                               cout<<setfill('=')<<setw(80)<<"=";
                               return;
         }
         else
         {
             for(unsigned int i=0;i<vEntries.size();i++)
             {
                     vEntries[i].ordernum=(i+1);
                     cout<<"\n\t\t\tOrder Number:\t\t"<<vEntries[i].ordernum;
                     cout<<"\n\t\t\tName:\t\t\t"<<vEntries[i].name;
                     cout<<"\n\t\t\tCell Phone Number:\t"<<vEntries[i].cnumber;
                     cout<<"\n\t\t\tHome Phone Number:\t"<<vEntries[i].hnumber;
                     cout<<"\n\t\t\tAddress:\t\t"<<vEntries[i].address<<endl;
             }
             cout<<endl;
             cout<<setfill('=')<<setw(80)<<"=";
         }
    }

  7. #7
    Registered User
    Join Date
    Apr 2003
    Posts
    2,663
    your right... but i have to clear the string for some reason for it to work
    Doing this:
    Code:
    temp.name.clear();
    is the same as doing this:
    Code:
    temp.name = "";
    and in your program it has absolutely no effect since you do this:
    Code:
    temp.name=first+" "+last;
    What you are doing can be boiled down to this:
    Code:
    string str = "start text";
    str = "";
    str = "new text";
    which has the same effect as:
    Code:
    string str = "start text";
    str = "new text";
    So, no, you don't have use clear() to erase the string for your code to work.

    so the stream works once...but it should work multiple times because i clear it after i am done each time
    Are you aware that there is a distinction between a string and a stream? I don't see anywhere in your code where you are clearing a stream.

    When you read from a file, if any errors occur while you are reading from the file, an error flag is set which will prevent you from reading from the file anymore. Reaching eof is considered an error, and it causes an error flag to be set. Similarly, if you read the end of a stringstream, an error flag is set. You can use a stream's clear() function to reset all the error flags for the stream and then attempt to read from the stream again.
    Last edited by 7stud; 05-26-2006 at 06:53 PM.

  8. #8
    Registered User
    Join Date
    Apr 2005
    Posts
    76
    Doing this:

    Code:
    temp.name.clear();
    is the same as doing this:

    Code:
    temp.name = "";
    well all i know is that when i had my code like this... it didnt work right... and it displayed the whole string stream.. not the string i wanted...

    Code:
             while(getline(fFile,temp.name))
             {
                       getline(fFile,temp.cnumber);
                       getline(fFile,temp.hnumber);
                       getline(fFile,temp.address);
                       
                       s.str(temp.name);
                       //temp.name.clear();
                       s >> heading >> first >> last;
                       temp.name=first+" "+last;
                       s.str("");
                       
                       s.str(temp.cnumber);
                       //temp.cnumber.clear();
                       s >> heading >> temp.cnumber;
                       s.str("");
                       
                       s.str(temp.hnumber);
                       //temp.hnumber.clear();
                       s >> heading >> temp.hnumber;
                       s.str("");
                       
                       s.str(temp.address);
                       //temp.address.clear();
                       s >> heading >> temp.address;
                       s.str("");
                       
                       vEntries.push_back(temp);
    when i had my code like this, not clearing the string, it didn't display properly

    (it would do this...
    Name: Name: Joe Dirt
    and with the clear() it does this...
    Name: Joe Dirt)

    ... im guessing that the >> operator, in this case, is the same as a += not a =...although please correct me if i am wrong.. once i again, i am very new at string streams...

    and in your program it has absolutely no effect since you do this:

    Code:
    temp.name=first+" "+last;
    Well, I was just doing Joe(space)Dirt... how is this wrong? Wouldn't it just be JoeDirt if i didn't include the space?

    Are you aware that there is a distinction between a string and a stream? I don't see anywhere in your code where you are clearing a stream.

    When you read from a file, if any errors occur while you are reading from the file, an error flag is set which will prevent you from reading from the file anymore. Reaching eof is considered an error, and it causes an error flag to be set. Similarly, if you read the end of a stringstream, an error flag is set. You can use a stream's clear() function to reset all the error flags for the stream and then attempt to read from the stream again.
    Oh, i was unaware of using clear() for string streams.. i went to this website and it said you could use s.str(""); ...
    Here it is!

  9. #9
    Registered User
    Join Date
    Apr 2003
    Posts
    2,663
    Look at this code:
    Code:
    temp.name.erase( 0 , 8 );
    ....
    ...
    temp.name.clear();
    1)Describe what you think this does:
    Code:
    temp.name.erase( 0 , 8 );
    2) Describe what you think this does:
    Code:
    temp.name.clear();
    -----
    ... im guessing that the >> operator, in this case, is the same as a += not a =...although please correct me if i am wrong..
    Well, why don't you write some code to test that theory.
    -----
    Code:
    while(getline(fFile,temp.name))
     {
    		   getline(fFile,temp.cnumber);
    		   getline(fFile,temp.hnumber);
    		   getline(fFile,temp.address);
    		   
    		   s.str(temp.name);
    		   //temp.name.clear();
    		   s >> heading >> first >> last;
    		   temp.name=first+" "+last;
    		   s.str("");
    		   
    		   s.str(temp.cnumber);
    		   //temp.cnumber.clear();
    		   s >> heading >> temp.cnumber;
    		   s.str("");
    		   
    		   s.str(temp.hnumber);
    		   //temp.hnumber.clear();
    		   s >> heading >> temp.hnumber;
    		   s.str("");
    		   
    		   s.str(temp.address);
    		   //temp.address.clear();
    		   s >> heading >> temp.address;
    		   s.str("");
    		   
    		   vEntries.push_back(temp);
    when i had my code like this, not clearing the string, it didn't display properly
    There is no code there that displays anything.

    As an exercise, try this code:
    Code:
    string str = "start text";
    str.clear();
    str = "new text";
    cout<<str<<endl;
    Examine the output and then comment out the second line and see if it makes any difference to the value stored in str. What conclusions can you draw from that about your temp.name.clear() line?
    Last edited by 7stud; 05-27-2006 at 01:29 AM.

  10. #10
    Registered User
    Join Date
    Apr 2005
    Posts
    76
    1) Well from what I know, it erases the characters in a string from a starting position ( 0 ) and then it erases so many characters ( 8 ).

    2) It clears the whole string?

    There is no code there that displays anything.
    I'm sorry, I posted the display function in a previous post.

    Code:
    /***********************************/
    /**** Phonebook::DisplayEntries ****/
    /***********************************/
    void Phonebook::DisplayEntries()
    {
         if(vEntries.size()==0)
         {
                               cout<<"\n\t\t\t\t  >FILE EMPTY<";
                               cout<<endl<<endl;
                               cout<<setfill('=')<<setw(80)<<"=";
                               return;
         }
         else
         {
             for(unsigned int i=0;i<vEntries.size();i++)
             {
                     vEntries[i].ordernum=(i+1);
                     cout<<"\n\t\t\tOrder Number:\t\t"<<vEntries[i].ordernum;
                     cout<<"\n\t\t\tName:\t\t\t"<<vEntries[i].name;
                     cout<<"\n\t\t\tCell Phone Number:\t"<<vEntries[i].cnumber;
                     cout<<"\n\t\t\tHome Phone Number:\t"<<vEntries[i].hnumber;
                     cout<<"\n\t\t\tAddress:\t\t"<<vEntries[i].address<<endl;
             }
             cout<<endl;
             cout<<setfill('=')<<setw(80)<<"=";
         }
    }
    string str = "start text";
    str.clear();
    str = "new text";
    cout<<str<<endl;
    I get what your saying when you make a str = "some text"; which changes the value of str...

    But, is this the same thing as STRSTR<<str; in a string stream?

    Because the only place that I actually set a string to a string (=) is in the name test.name=first+" "+last.

    And like I said before. When I did not use the clear() function in my code... the strings displayed the WHOLE string stream... not just the string i wanted.

    Code:
    while(getline(fFile,temp.name))
     {
    		   getline(fFile,temp.cnumber);
    		   getline(fFile,temp.hnumber);
    		   getline(fFile,temp.address);
    		   
                                       // Doesn't display what i want
    
    		   s.str(temp.name);
    		   s >> heading >> first >> last;
    		   temp.name=first+" "+last;
    		   s.str("");
    		   
    		   s.str(temp.cnumber);
    		   s >> heading >> temp.cnumber;
    		   s.str("");
    		   
    		   s.str(temp.hnumber);
    		   s >> heading >> temp.hnumber;
    		   s.str("");
    		   
    		   s.str(temp.address);
    		   s >> heading >> temp.address;
    		   s.str("");
    		   
    		   vEntries.push_back(temp);
    And to see if this helps with anything... I will post my .txt file that I am reading from.

    Code:
    Name:			John Doe
    Cell Phone Number:	123-4567
    Home Phone Number:	890-1234
    Address:		123 Abc Dr.
    
    Name:			Joe Dirt
    Cell Phone Number:	222-2222
    Home Phone Number:	333-3333
    Address:		131 Yoo Ct.
    I mean I could always quit trying with the Formatted Data File and just use characters to divide the strings...like I usually do... but that defeats the purpose of the user being able to keep the .txt file on his desktop and read from it without trouble...
    Last edited by gL_nEwB; 05-27-2006 at 10:29 AM.

  11. #11
    (?<!re)tired Mario F.'s Avatar
    Join Date
    May 2006
    Location
    Ireland
    Posts
    8,446
    I'm yet to learn about streams in C++. Still very green on my C++ learning. Doing it slowly. I have the time. So, sorry if I can't help with the actual code.

    However, you have your file clearly delimited. Perhaps you are just not seeing it. All data you want to extract starts at a specific point on each line. You extract the line to a temporary string variable and then skip through the string until you reach that position.

    Alternatively you could place the colon at the start of the data you want extracted, instead of at the end of the label. That way you would also have a delimiter symbol, you could use to search.
    Code:
    Name			:John Doe
    Cell Phone Number	:123-4567
    Home Phone Number	:890-1234
    Address		        :123 Abc Dr.
    And yet, a third option, and my favorite, to have another file (a binary file preferably) with the data defined to your liking (no need for labels, for instance). The user formated file could then be tampered with by anyone and it would not break your program. Of course this means you would have to write to the user file too when updating data.
    Last edited by Mario F.; 05-27-2006 at 11:40 AM.

  12. #12
    Registered User
    Join Date
    Apr 2003
    Posts
    2,663
    I would first display the data you are reading from the file to see that it is correct. So, do something like this:
    Code:
    while(getline(fFile,temp.name))
    {
    		getline(fFile,temp.cnumber);
    		getline(fFile,temp.hnumber);
    		getline(fFile,temp.address);
    					
    		cout<<temp.name<<endl;
    		cout<<temp.cnumber<<endl;
    		cout<<temp.hnumber<<endl;
    		cout<<temp.address<<endl;
    Then you should verify that this code works:
    Code:
    #include <iostream>
    #include <string>
    #include <sstream>
    using namespace std;
    
    
    int main()
    {
    
    	stringstream s;
    	
    	string EntryName;
    	string heading, first, last;
    
    	string nameFromFile = "Name:			John Doe";
    
    	s.str(nameFromFile);
    	s>>heading>>first>>last;
    	EntryName = first + " " + last;
    	
    	cout<<EntryName<<endl;
    
    	return 0;
    }
    Finally, if you know the >> operator reads one word at a time from a stream(that's what skipping leading whitespace and stopping at trailing whitespace means), would that code work for a heading like this:
    Cell Phone Number

  13. #13
    Registered User
    Join Date
    Apr 2005
    Posts
    76
    haha you must have read my mind... I was getting frustrated trying to use string streams... so yea, I am just gonna use getline to get the heading "Name(spaces):" and store in a temp heading variable and then get the actual data with getline as well....

    And my reason for having a separate display function... is cause thats just a short snippet from my code. I retrieve data from the file... then only display the data at the request from the user.
    Last edited by gL_nEwB; 05-27-2006 at 01:02 PM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. String Class
    By BKurosawa in forum C++ Programming
    Replies: 117
    Last Post: 08-09-2007, 01:02 AM
  2. += operator
    By BKurosawa in forum C++ Programming
    Replies: 8
    Last Post: 08-05-2007, 03:58 AM
  3. Classes inheretance problem...
    By NANO in forum C++ Programming
    Replies: 12
    Last Post: 12-09-2002, 03:23 PM
  4. creating class, and linking files
    By JCK in forum C++ Programming
    Replies: 12
    Last Post: 12-08-2002, 02:45 PM
  5. Warnings, warnings, warnings?
    By spentdome in forum C Programming
    Replies: 25
    Last Post: 05-27-2002, 06:49 PM