Dismiss Notice
Join Physics Forums Today!
The friendliest, high quality science and math community on the planet! Everyone who loves science is here!

C++: Finding a Newline Character in a Sensible Way

  1. Apr 4, 2012 #1
    I am not sure how to do this:

    I have a text file that I have assigned to an ifstream object. The text file looks something like:

    Code (Text):

    Header1    Header2    Header3 .... HeaderN
    data1        data2        data3    .... dataN
    .
    .
    .
     
    I want to read the data into an array of structs. So I need to determine how many headers there are if I don't know in advance.

    I am not sure of the best way to do this? I thought that I could just cin the data into a variable while incrementing a counter variable until I encounter a newline character. But I don't know if cin will actually read in a newline or if it will just skip over it? I think the latter.

    Any thoughts?
     
  2. jcsd
  3. Apr 4, 2012 #2

    AlephZero

    User Avatar
    Science Advisor
    Homework Helper

    You can use getline() to read a complete line from the file into a string.

    Then process the contents of the string. You might want to use an istringstream, so you can do I/O operations on the data in the string to count the fields, read the data items, etc.
     
  4. Apr 4, 2012 #3

    jtbell

    User Avatar

    Staff: Mentor

    Right, the stream extraction operator >> treats all whitespace (blanks, tabs, newlines) the same way, so you can't use it to "catch" the end of a line. You have to use getline(), or else read one character at a time using cin.get().

    If you're using the C++ string data type instead of C-style char* "strings", use the standalone getline() function: getline(cin, yourstring) .
     
  5. Apr 4, 2012 #4
    You might also look into use of vector of strings if you prefer to read the first line into a string stream then extract each word into the declared vector. This isn't the best way since you call at least 3 constructors but it would resolve your problem.
     
  6. Apr 6, 2012 #5
    Hi folks :smile: Thanks for the input. With your guidance and some searching around I have this. It's almost there:

    Code (Text):

    #include <iostream>
    #include <fstream>
    #include <sstream>
    int main ()
    {
        using namespace std;
        string filename = "test.txt";

        ifstream inputFile;
        // Bind test.txt to inputFile object
        inputFile.open( filename.c_str() );
        if ( inputFile.fail() )
        {
            cerr << "Problem opening file ... ";
        }
       
        string stringToSplit;
        // Use getline to assign 1st line of text to string
        getline(inputFile, stringToSplit);
        // Use istringstream class op>> to extract formatted text
        istringstream iss(stringToSplit);
       
        while ( iss )
        {
            string sub;
            iss >> sub;
            cout << "Substring: " << sub << endl;
        }  
        return 0;
    }

     
    (*Note that 'test.txt' contains the single line of text: "What is happening".)
    The loop seems to execute 1 more time than necessary, as this is the output:

    Code (Text):

    Program loaded.
    run
    [Switching to process 613]
    Running…
    Substring: What
    Substring: is
    Substring: happening
    Substring:

    Debugger stopped.
    Program exited with status value:0.
     
    Admittedly, the definition of the istringstream class is a little over my head right now, so that I am not entirely sure what the statement if ( iss ) is testing for.

    Any thoughts?
     
  7. Apr 6, 2012 #6

    Hurkyl

    User Avatar
    Staff Emeritus
    Science Advisor
    Gold Member

    The loop executes exactly as many times as it should. The problem is that your write statement is executed before you check whether your read statement hit end of stream.

    istringstream is n istream, just like cin. Reading from one is pretty much just like reading from the other.


    99 out of 100, if you are getting weird behavior when doing I/O, it's because you got the error checking wrong. :smile:
     
  8. Apr 6, 2012 #7

    AlephZero

    User Avatar
    Science Advisor
    Homework Helper

    A stringstream behaves just the same as if you were reading a file that with the contents of the string. When try to read past the end of the string, you get the same "end of file" inidications as for a real file.

    The last time through your loop, you hit the end of the string so iss >> sub produces an empty string. You then print that, and then you test for "end of string" next time you go through the while statement.

    The best way to fix this is the same as for any "reading a file when you don't know how much data there is" situation: test for "end of file" when you try to read the next item, not later on in the code. The neatest way is often to put the "iss >> whatever" in the "while( )" statement, and the code to do something with the data inside the loop. If that isn't possible, you can test the status of iss and leave the loop with a "break" statement.

    Edit: I guess Hurkyl types faster than I do!
     
  9. Apr 6, 2012 #8

    This seems to do it, but I am not sure if I am just masking some other issue. Trying to think ahead a little bit here. Is this what you had in mind? Or am I way off?

    Code (Text):
    #include <iostream>
    #include <fstream>
    #include <sstream>
    int main ()
    {
        using namespace std;
        string stringToSplit ="What happened";

        istringstream iss(stringToSplit);
        while ( iss )
        {
            string sub;
                    iss >> sub;
                    if (iss)
                   {
                           cout << "Substring: " << sub << endl;
                   }
        }
        return 0;
    }
     
     
  10. Apr 6, 2012 #9

    Hurkyl

    User Avatar
    Staff Emeritus
    Science Advisor
    Gold Member

    This code looks correct. However, rather than duplicate testing iss in two different places, I would replace the while test with an infinite loop -- the while(true) -- and when the other test fails, use break.
     
  11. Apr 7, 2012 #10

    jtbell

    User Avatar

    Staff: Mentor

    How about this:

    Code (Text):

        istringstream iss(stringToSplit);
        string sub;
        while (iss >> sub)
        {
            cout << "Substring: " << sub << endl;
        }
     
     
Know someone interested in this topic? Share this thread via Reddit, Google+, Twitter, or Facebook




Similar Discussions: C++: Finding a Newline Character in a Sensible Way
Loading...