Reputation: 33
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
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
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+)?
std::smatch
ref
which contains at position 0 the entire search string and further indices contain the found groups
ReadNumber
function read line from file and get from line NUMBER
or [NUMBER, NUMBER]
match_results
which are converted to int by match group
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
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
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