Comments and effectively using getline(f, line) with >> operator

I am trying to make a config file that has the capability of detecting that a line in it is a comment if it has a '#' in it.

Here's the working code I have right now.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
#include <fstream>
#include <string>

int main()
{
    std::string filename;
    std::string equals;
    std::string path;
    std::ifstream f("find_comment.txt");
    
    std::string line;
    while (getline(f, line))
    {
        //detect if '#' is in the line
        if (line.length() > 0 && line.find('#') != std::string::npos)
            std::cout << "#some unread comment" << std::endl;
        else
            std::cout << line << std::endl;  
    }
}

Output:
#some unread comment
file.dat  = ./data/some_file.dat
file2.dat = ./data/file2.dat
file3.dat = ./data/file3.dat

#some unread comment
enemy.png  = ./images/monster.png
player.png = ./images/hero.png


Here is find_comment.txt:
1
2
3
4
5
6
7
8
#a category of config files
file.dat  = ./data/some_file.dat
file2.dat = ./data/file2.dat
file3.dat = ./data/file3.dat

#another category
enemy.png  = ./images/monster.png
player.png = ./images/hero.png


The issue is that I want to add a way for the program to actually read the elements in line if it isn't a comment. If I do something like this
1
2
3
4
5
6
7
8
9
...//see other code
        else
        {
            std::cout << line << std::endl;
            f >> filename; //std::strings
            f >> equals;
            f >> path;
            //add filename and path to some object to use later...
        }   

it obviously doesn't work because getline(f, line) already goes through the file each iteration, so using the >> operator messes everything up.

I did some searching, and it appears that turning the line back into a stream using std::stringstream can be done. I can figure out how to do it using this stringstream method, but this seems so over-the-top.

So, basically, I'm asking if there is a better way to read through the file like this, or do I have to use getline(), and then change the line back into a stream so that >> can be used? It just seems so redundant.

Thanks for reading, hope this makes sense...
f.peek() might help.
you could also parse through the line. ill whip up an example real qiuck

edit:

1
2
3
4
5
6
7
8
9
bool find(const std::string &Buffer, const char &Delimiter) {
    for(char &Iterator : Buffer) {
        if(Iterator == Delimiter) {
            return false;
        }
    }

    return true;
}
Last edited on

it obviously doesn't work because getline(f, line) already goes through the file each iteration, so using the >> operator messes everything up.

That's correct, you've already read the line from the file so any additional extractions will get new information from the file, not work with the information you've already retrieved.

I did some searching, and it appears that turning the line back into a stream using std::stringstream can be done.


That's probably the best way since you've already read the line into a string.

I can figure out how to do it using this stringstream method, but this seems so over-the-top.

Why does this seem like it's over the top? You have a string that contains the information, to why not process that string to retrieve the information into the proper variables?

Last edited on
It just seemed over the top at first because I felt like it shouldn't need to do this "translation" back and forth, and instead should have a way to set the "reading position" back to the beginning of the line, if it doesn't encounter a "comment line" (if that didn't make sense, don't worry about it). But something built-in like that wouldn't serve a broad use.

@yay295, sorry peek wouldn't work very well unless the # is at the very beginning, the code I have just sees if the hash is anywhere in the line.

Okay, almost done here, just got a really stupid problem happening, I'm sure there's some easy fix...
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
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>

int main()
{
    std::string filename;
    std::string equals;
    std::string path;
    std::ifstream f("find_comment.txt");
    
    std::string line;
    while (getline(f, line))
    {
        if (line.length() > 0 && line.find('#') != std::string::npos)
        {
            std::cout << "#some unread comment" << std::endl;
        }
        else
        {
            std::stringstream stream;
            stream << line;
            
            stream >> filename;
            stream >> equals;
            stream >> path;
            std::cout << filename << " " << equals << " " << path << std::endl;
        }   
    }
}

1
2
3
4
5
6
7
8
9
//file
#a category of config files
file.dat  = ./data/some_file.dat
file2.dat = ./data/file2.dat
file3.dat = ./data/file3.dat

#another category
enemy.png  = ./images/monster.png
player.png = ./images/hero.png

The problem here is that, in the program, the output repeats the printing of "file3.dat = ./data/file3.dat" for every line in between that and the "#another category" line. Meaning that it keeps taking in the stream data from the previous line, I'm not sure why that's happening. For example, if I have it so there's 10 blank lines in between "file3.dat..." and "#another category", it will print "file3.dat = ./data/file3.dat" 10 times because of something the stringstream is doing.

EDIT:
I changed the else statement to else if (line.length() > 0). Seems to work fine now. Thanks everyone.

...gah still doesn't work if there's whitespace like spaces.
Last edited on
Would this work?
1
2
3
4
5
6
7
8
9
10
11
12
while ( f >> filename )
{
    if ( filename[0] == '#' )
        getline ( f, filename );

    else
    {
        f >> equals;

        f >> path;
    }
}
I got it to account for white space by doing
1
2
3
4
5
6
7
8
9
bool onlyContainsSpaces(std::string line)
{
    for (int i = 0; i < line.length(); i++)
    {
        if (line[i] != ' ')
            return false;
    }
    return true;
}

and then
else if (line.length() > 0 && !onlyContainsSpaces(line))


Just tested your code Yay295:
WOW Yay295 that seems to work great. It seems to handle whitespace before and after the comment fine due to the stream as well!! Thanks! That's genius that it uses the rest of the "comment line" using getline before it discards that at the beginning of the next iteration.
Last edited on
Topic archived. No new replies allowed.