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]
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 <<.
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);
}
}
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
Related
There's a series of coordinates I'm trying to write to an array so I can perform calculations on, but I haven't been able to read the file correctly since I can't ignore the headers, and when I do remove the headers it also doesn't seem to correctly write the values to the array.
The coordinate file is a txt as below.
Coordinates of 4 points
x y z
-0.06325 0.0359793 0.0420873
-0.06275 0.0360343 0.0425949
-0.0645 0.0365101 0.0404362
-0.064 0.0366195 0.0414512
Any help with the code is much appreciated. I've tried using .ignore to skip the two header lines but they don't seem to work as expected.
#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
using namespace std;
int main() {
int i = 1;
int count = 1;
char separator;
const int MAX = 10000;
int x[MAX];
int y[MAX];
int z[MAX];
int dist[MAX];
char in_file[16]; // File name string of 16 characters long
char out_file[16];
ifstream in_stream;
ofstream out_stream;
out_stream << setiosflags(ios::left); // Use IO Manipulators to set output to align left
cout << "This program reads a series of values from a given file, saves them into an array and performs calculations." << endl << endl;
// User data input
cout << "Enter the input in_file name: \n";
cin >> in_file;
cout << endl;
in_stream.open(in_file, ios::_Nocreate);
cout << "Enter the output file name: \n";
cin >> out_file;
cout << endl;
out_stream.open(out_file);
// While loop in case in_file does not exist / cannot be opened
while (in_stream.fail()) {
cout << "Error opening '" << in_file << "'\n";
cout << "Enter the input in_file name: ";
cin >> in_file;
in_stream.clear();
in_stream.open(in_file, ios::_Nocreate);
}
while (in_stream.good) {
in_stream.ignore(256, '\n');
in_stream.ignore(256, '\n');
in_stream >> x[i] >> separator >>y[i] >> separator >> z[i];
i++;
count = count + 1;
}
cout << x[1] << y[1] << z[1];
in_stream.close();
out_stream.close();
return 0;
}
Within your reading of the file, you are using in_stream.ignore(256, '\n'); correctly, but you want to use it outside the while loop. When you have it inside the while loop, every time it runs, you will ignore the first two lines, then read the third. Your output would actually read in only a third of what you expect. To fix this, just move those 2 lines outside the while loop.
in_stream.ignore(256, '\n');
in_stream.ignore(256, '\n');
while (in_stream.good)
{
in_stream >> x[i] >> separator >>y[i] >> separator >> z[i];
i++;
count = count + 1;
}
This should fix your problem, but you should generally use a vector instead of an array. Vectors automatically manage memory and check for bounds instead of you having to do that.
Also, good practice is to read values out of the stream as the while condition instead of in_stream.good:
while(stream >> var)
{
//Your code here
}
Here is a good resource on why that is.
I am a beginner in C++. This is an assignment I am completing therefore I must use a the function problem1() as there is another function that I need to create to find max and min. The following text file was provided to me for the assignment.
I am having a hard time with having the program read a text file that contains a set of numbers such as the following :
[253, 676, 114]
[527, 160, 277]
[364, 193, 169]
[246, 651, 378]
[536, 479, 695]
[569, 548, 83]
my code is :
using namespace std;
void problem1(string);
int main()
{
string s= "data2.txt";
problem1(s);
return 0;
}
void problem1(string s)
{
double num, sum = 0, avg;
int count=0;
ifstream file;
file.open(s);
if (file.is_open())
{
while(file>>num)
{
sum= sum + num;
count++;
}
avg= sum/count;
cout <<"Average is " << avg << endl;
file.close();
}
}
It works for text files that contine the numbers without [].
For example:
text file contains the following..
1
2
3
4
5
and finds the avg of 3.
If you look at one line of the input file, then you will see the following. It consists of
opening square bracket
first number
comma
second number
comma
third number
closing bracket
If you want to read the line and all lines in a file, then you must read everything. For the character that you are not interested in, you could use a char temp temporary variable and read those characters into it, like so:
fileStream >> temp >> first >> temp >> second >> temp >> third >> temp;
Of course you can use also more "speaking" and separate variables like so:
fileStream >> openingBracket >> first >> comma1 >> second >> comma2 >> third >> closingBracket;
Then you could also validate in an if statement, if the variables contain the expected values:
if (openingBracket == '[' and comma1 == ',' and comma2 ==',' and closingBracket==']') ....
But forget this at the moment.
So, now we know how to read a line. If we want to read all lines, we put the above statement in a while. This will then run, until it hits an End-Of-File or some other error occurs.
In the while loop body, you can do your calculations. And after the while loop body, you can output the resulting average as a double value.
Please note:
The constructor of the std::ifstream opens the file for you automatically. The destructor will close it automatically
The bool operator of the streams is overwritten. It returns, if the state is ok, or if one of the status bits is set. Therefore if (fileStream) is sufficient for a check.
the extractor operator >> returns a reference to the stream. So, if you write fileStream >> openingBracket then the result will be "fileStream", this will be used for the next extraction operation fileStream >> first and so on and so on. At the end, you will have something similar like while(fileStream). And this will run until "eof" or other failure bits are set. (See bool operator above).
Your whole program could then look like this:
#include <iostream>
#include <fstream>
#include <string>
void problem1(std::string fileName) {
// Open the file
std::ifstream fileStream{ fileName };
// Check, if everything is ok with the stream
if (fileStream) {
// These are dummy variables
char openingBracket{}, comma1{}, comma2{}, closingBracket{};
// The values in one line
int first{}, second{}, third{};
// For summing up and claculating the average
int sum{}, counter{};
// Read data, as long as there are any
while (fileStream >> openingBracket >> first >> comma1 >> second >> comma2 >> third >> closingBracket) {
// Do the necessary calculations
sum += first + second + third;
counter += 3;
}
// Output avaerage value as double
std::cout << "Average is " << static_cast<double>(sum) / static_cast<double>(counter) << '\n';
}
}
int main() {
std::string s = "data2.txt";
problem1(s);
return 0;
}
Edit:
Searching for max and min:
#include <iostream>
#include <fstream>
#include <string>
#include <limits>
void problem1(std::string fileName) {
// Open the file
std::ifstream fileStream{ fileName };
// We want to know the min max value
int max = std::numeric_limits<int>::min();
int min = std::numeric_limits<int>::max();
// Check, if everything is ok with the stream
if (fileStream) {
// These are dummy variables
char openingBracket{}, comma1{}, comma2{}, closingBracket{};
// The values in one line
int first{}, second{}, third{};
// For summing up and claculating the average
int sum{}, counter{};
// Read data, as long as there are any
while (fileStream >> openingBracket >> first >> comma1 >> second >> comma2 >> third >> closingBracket) {
// Do the necessary calculations
sum += first + second + third;
counter += 3;
if (first > max) max = first;
if (second > max) max = second;
if (third > max) max = third;
if (first < min) min = first;
if (second < min) min = second;
if (third < min) min = third;
}
// Output average value as double
std::cout << "Average is " << static_cast<double>(sum) / static_cast<double>(counter)
<< "\nMax = " << max << "\nMin = " << min << '\n';
}
}
I am trying to figure out how to extract values from a text file as a type double so that they can be used in calculations.
I have a text file that is formatted like:
parameter1 parameter2 parameter3
50 0 0.1
And I want to extract only the numbers.
This is one of my attempts (I have been working for hours trying to figure out how to do this).
#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
#include <sstream>
using namespace std;
int main()
{
const int MAX = 80;
char buffer[MAX];
string input;
double j;
ifstream param0;
param0.open("param0.txt");
char ch;
while (param0)
{
param0.get(ch);
cout << ch;
}
getline(param0, input);
param0 >> j;
while (param0)
{
cout << j << endl;
getline(param0, input);
param0 >> j;
}
return 0;
}
this code
char ch;
while (param0)
{
param0.get(ch);
cout << ch;
}
runs to the end of the file. All reads after it will return nothing. Either take this loop out or rewind the file param0.rewind()
The basic idea of the code should be:
std::string line;
double p1, p2, p3;
std::string more;
while (std::getline(in, line)) {
std::istringstream iss{line};
if (iss >> p1 >> p2 >> p3 && !(iss >> more)) {
std::printf("p1=%f, p2=%f, p3=%f\n", p1, p2, p3);
} else {
std::printf("invalid line: %s\n", line.c_str());
}
}
In plain words, the code says: a line is valid if it contains three numbers and nothing more.
C++ purists will say that I shouldn't use printf in C++, but I like the separation between formatting and the actual data.
suggestion :
best to check if you open the file correctly.
close the file once you finish with it.
you can just use the >> operator if you reading everything in one line. It doesn't matter if its string or double as long as if you pass the correct storage variable;
string param1;
string param2;
string param3;
double j,k,l;
ifstream file("test.txt",std::ios::in);
if (!file.is_open())
std::cout << "failed to open " << endl;
while (file)
{
file >> param1 >> param2 >>param3; // getting as strings
cout << param1 <<", "<< param2<<", "<< param3<<endl;
file >> j >> k >> l; //getting as doubles
cout << j <<", " << k <<", " << l<<endl;
}
file.close();
return 0;
output
parameter1, parameter2, parameter3
50, 0, 0.1
Let's say I have a text file:
83 71 69 97Joines, William B.
100 85 88 85Henry, Jackson Q.
And I want to store each number in an array of ints, and each full-name into an array of strings (a full name would be Joines, William B for example).
What would be the best way, because I debated whether using while (inputFile >> line) or while (getline(inputFile, line)) would be better. I don't know if it would be easier to read them one word at a time or read them one line at a time. My main problem will be splitting the 97Joines, William B. to 97 and Joines, William B. which I don't understand how to do in C++.
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
int main() {
int counter = 0;
int scores[40];
string names[10];
string filename, line;
ifstream inputFile;
cout << "Please enter the location of the file:\n";
cin >> filename;
inputFile.open(filename);
while (inputFile >> line) {
// if line is numeric values only, do scores[counter] = line;
// if it is alphabet characters only, do names[counter] = line;
//if it is both, find a way to split it // <----- need help figuring out how to do this!
}
inputFile.close();
}
You need to #include <cstdlib> for strtol I am sure there are better ways to do this but this is the only way I know and this is only for 97joines, and 85Henry,
string word; // to get joines,
string str; // for 97
string numword;
inputFile >> numword;
for(int k = 0; k < numword.length(); k++)
{
if(isdigit(numword[k]))
{
str = str + numword[k];
}
else
{
word = word + numword[k];
}
}
int num = strtol(str.c_str(), NULL, 0);
You can, given the file structure you have shown, read it like this:
int a, b, c, d;
std::string name;
for (int i = 0; i < 2; ++i)
{
// read the numbers
inputFile >> a >> b >> c >> d;
// read the name
std::getline(inputFile, name);
// do stuff with the data... we just print it now
std::cout << a << " " << b << " " << c << " " << d << " " << name << std::endl;
}
Since the numbers are space separated it is easy to just use the stream operator. Furthermore, since the name is the last part we can just use std::getline which will read the rest of the line and store it in the variable name.
You can try it here, using std::cin.
#include <iostream>
#include <string>
#include <fstream>
#include <cstring>
using namespace std;
int hmlines(ifstream &a){
int i=0;
string line;
while (getline(a,line)){
cout << line << endl;
i++;
}
return i;
}
int hmwords(ifstream &a){
int i=0;
char c;
while ((c=a.get()) && (c!=EOF)){
if(c==' '){
i++;
}
}
return i;
}
int main()
{
int l=0;
int w=0;
string filename;
ifstream matos;
start:
cout << "give me the name of the file i wish to count lines, words and chars: ";
cin >> filename;
matos.open(filename.c_str());
if (matos.fail()){
goto start;
}
l = hmlines(matos);
matos.seekg(0, ios::beg);
w = hmwords(matos);
/*c = hmchars(matos);*/
cout << "The # of lines are :" << l << ". The # of words are : " << w ;
matos.close();
}
The file that i am trying to open has the following contents.
Twinkle, twinkle, little bat!
How I wonder what you're at!
Up above the world you fly,
Like a teatray in the sky.
The output i get is:
give me the name of the file i wish to count lines, words and chars: ert.txt
Twinkle, twinkle, little bat!
How I wonder what you're at!
Up above the world you fly,
Like a teatray in the sky.
The # of lines are :4. The # of words are : 0
int hmwords(ifstream &a){
int i;
You've forgotten to initialize i. It can contain absolutely anything at that point.
Also note that operator>> on streams skips whitespace by default. Your word counting loop needs the noskipws modifier.
a >> noskipws >> c;
Another problem is that after you call hmlines, matos is at end of stream. You need to reset it if you want to read the file again. Try something like:
l = hmlines(matos);
matos.clear();
matos.seekg(0, ios::beg);
w = hmwords(matos);
(The clear() is necessary, otherwise seekg has no effect.)
Formatted input eats whitespaces. You can just count tokens directly:
int i = 0;
std::string dummy;
// Count words from the standard input, aka "cat myfile | ./myprog"
while (cin >> dummy) ++i;
// Count files from an input stream "a", aka "./myprog myfile"
while (a >> dummy) ++i;