FancyPants General
FancyPants General

Reputation: 33

C++ how to ignore string while reading from file?

I have a program that opens a file, reads from the file and I need to ignore the strings from the file and save only the integers into variables. So far I have tried with file.ignore(' '), but it ignores only the first line. Does anyone has an idea how I can fix this?

My code is:

ifstream file1;
int num1, num2, num3;
int intervalNumber1, intervalNumber2, intervalNumber3;
file1.open("file1.txt");
if (file1.fail()) {
    cout << "Error" << endl;
    exit(1);
} else {
    if (file1.is_open()) {
        file1 >> num1;
        file1 >> num2;
        file1 >> num3;

        file1 >> intervalNumber1;
        file1 >> intervalNumber2;
        file1 >> intervalNumber3;
    }
}

File1.txt

Number 40
Number1 34
Number2 100

Interval Number [20, 50]
Interval Number1 [60, 100]
Interval Number2 [110, 300]

Upvotes: 0

Views: 1899

Answers (3)

arutar
arutar

Reputation: 1093

Similar actions using regular expressions

i am using two classes std::regex (std regular expression class), std::smatch (match results class) and algorithm regex_search. To read lines from a file, I use the getNewLine function, which skips empty lines

  1. std::regex ref where I apply a pattern that is suitable for both cases NUMBER and [NUMBER, NUMBER]. In all cases, the numbers are placed in separate groups. Pattern: [ \\[](\\d+)[ ,]*(\\d+)?

  2. std::smatch ref which contains at position 0 the entire search string and further indices contain the found groups

  3. ReadNumber function read line from file and get from line NUMBER or [NUMBER, NUMBER] match_results which are converted to int by match group

  4. stoi ref function converts found string of digits to int

#include <iostream>
#include <regex>
#include <fstream>

using namespace std;

ifstream file1;
regex re("[ \\[](\\d+)[ ,]*(\\d+)?");

bool getNewLine(ifstream& f, string& s) {
    while (getline(f, s)) 
        if (!s.empty()) return true;
    
    return false;
}

/*
*     t1 and t2 pointers for numbers read from the file, 
*     if t2 is nullptr then only one number is needed
*/
void ReadNumber(int *n1, int *n2=nullptr) {
    smatch m;
    string newLine;

    if (!getNewLine(file1, newLine))
        exit(1);

    //Checking if a string contains a match
    if (!regex_search(newLine, m, re))
        exit(1);

    *n1 = stoi(m[1]);
    cout << *n1;

    if (n2) {
        //Checking that the second group contains digits
        if(!m[2].length())
            exit(1);

        *n2 = stoi(m[2]);
        cout << " " << *n2;
    }

    cout << endl;
}

int main()
{
    const int ArrSize = 3;
    int Numbers[ArrSize] = { 0,0,0 };
    pair<int, int> intervalNumber[ArrSize] = { {0,0},{0,0},{0,0} };

    file1.open("c:\\file1.txt");

    if (file1.fail()) {
        cout << "Error" << endl;
        exit(1);
    }

    for (int i = 0; i < ArrSize; i++)
        ReadNumber(&Numbers[i]);

    for (int i = 0; i < ArrSize; i++)
        ReadNumber(&(intervalNumber[i].first), &(intervalNumber[i].second));

    file1.close();
    return 0;
}

results

40
34
100
20 50
60 100
110 300

Upvotes: 0

Chris G.
Chris G.

Reputation: 846

You might want to use a regular expression to solve this, if there is a known pattern.

If you just want to extract all numeric characters, using std::copy_if to another array (eg a string) would do the job.

Another direct and performant option is, to read the file content into an array, (eg std::string) and iterate over the content, checking for numbers.

std::string file_content (... load file content);
for(char& c : file_content) {
    if (isdigit(c)) {
        have_fun_with_digit(c);
    }
}

Upvotes: 1

463035818_is_not_an_ai
463035818_is_not_an_ai

Reputation: 122133

The simple approach is to read the strings the same way you read the integers. Assuming the format of the file is always the same and there is one word in the first the lines and two words in the next three lines and numbers are enclosed in [] and seperated by , you can just read the strings and the [ and ] and , in a char:

#include <sstream>
#include <utility>
#include <iostream>

int main() {
    std::stringstream ss{R"(Number 40
Number1 34
Number2 100

Interval Number [20, 50]
Interval Number1 [60, 100]
Interval Number2 [110, 300])"};

    std::string dummy_string;
    char dummy_char;
    int number0=0;
    int number1=0;
    int number2=0;
    std::pair<int,int> interval0;
    std::pair<int,int> interval1;
    std::pair<int,int> interval2;

    ss >> dummy_string >> number0;
    ss >> dummy_string >> number1;
    ss >> dummy_string >> number2;
    ss >> dummy_string >> dummy_string >> dummy_char >> interval0.first >> dummy_char >> interval0.second >> dummy_char;
    ss >> dummy_string >> dummy_string >> dummy_char >> interval1.first >> dummy_char >> interval1.second >> dummy_char;
    ss >> dummy_string >> dummy_string >> dummy_char >> interval2.first >> dummy_char >> interval2.second >> dummy_char;

    std::cout << number0 << " " << number1 << " " << number2 << "\n";
    std::cout << interval0.first << " " << interval0.second << "\n";
    std::cout << interval1.first << " " << interval1.second << "\n";
    std::cout << interval2.first << " " << interval2.second << "\n";

}

Output:

40 34 100
20 50
60 100
110 300

Reading from a file stream instead of the string stream works the same.


You should consider to use a std::vector instead of naming variables foo0,foo1, foo2 etc. Also consider to use a custom struct, for example if the numbers and the intervals belong together:

struct my_data {
    int number;
    int interval_start;
    int interval_stop;
};

For this type you can then overload the input operator <<.

Upvotes: 1

Related Questions