Search code examples
c++fileparsing

How to parse text from the file into two different variable


I have a text file, here it is:

a 0.240741
; 0.037037
k 0.0925926
s 0.222222
l 0.0925926
d 0.314815
ЏЌд|.–&Фsнcп—#

I need to assign first part of text(char and their frequency) to unordered map, and rest of text(ЏЌд|.–&Фsнcп—#) to string variable.How to do this?

I have a structure:

struct data_maps {
    unordered_map<char, double> char_prob; 
    unordered_map<char, string> char_haffcode; 
    string haffcode_all; 
    string ascii_char; 
};

Code, that supposed to parse the file and assign text to the variables

data_maps parsing_file(string text)
{
    data_maps data;
    ifstream file(text);

    char ch;
    double prob;
    streampos currentPosition;
    if (file.is_open()) {
        while (file >> ch >> prob)
        {
            data.char_prob[ch] = prob;
            streampos currentPosition = file.tellg();
        }

        
        file.seekg(currentPosition);

        string temp;
                while (getline(file,temp)) {
                     data.ascii_char += temp;
                }
    }
    else
        cerr << "Error:file have not opened.";
    return data;
}

When i executing this:

data_maps maps;
maps = parsing_file("D:\\HC_test\\testing.cmph");
for (auto pair : maps.char_prob)
{
    cout << pair.first << " " << pair.second << endl;
}   
cout << maps.ascii_char;

i have this output:

a 0.240741
; 0.037037
k 0.0925926
s 0.222222
l 0.0925926
d 0.314815

Solution

  • while (file >> ch >> prob) reads from the file until you reach the last line where it fails to extract a double. Recovering from that is complicated because the stream is in an error state and you already consumed the character but what you actually need is the whole line1.

    Read lines from the file instead. I present only a rough outline and leave the rest for you (your code isn't missing much actually):

    std::string line;
    while(getline(file,line) {
    
       //attempt to read a character and a float:
       std::stringstream ss{line};
       if(ss >> ch >> prob) {
            // it was successful ... use ch and prob
       } else {
            // it was not.. use line
       }
    }
    

    Reading strings from the file always succeeds until you reach the end of the file. Extracting a character and a double fails only for the last line where you want to use the full line.


    1 I think your code correctly restores the position in the file but does not correctly reset the state of the stream and that's the reason fails to read the last line.