Converting string to floats; can't clear stringstream correctly? - c++

Disclaimer: I must use c++ 98
As part of a class assignment, I have been tasked to convert space-delimited strings into floats (then calculate a span with those floats, but that is irrelevant to my problem). The strings are coming from text files. If there are any discrepancies with the float, I am supposed to ignore it and consider it corrupted. For example, a text file could consist of a line that looks like this:
34.6 24.2 18.a 54.3 20.0 15.6
In this case, 18.a would simply be considered corrupt and no further manipulation has to be done to it.
Now, I am having a problem clearing my stringstream of corrupt data. For reference, here is my code:
#include <vector>
#include <limits>
#include <string>
#include <sstream>
#include <fstream>
#include <iostream>
using namespace std;
int main(int argc, char* argv[]) {
//Open file
ifstream infile("dataFile");
//Get all file input into a single string
string line;
string buffer;
while (getline(infile, buffer)) {
line += buffer + " ";
}
infile.close();
//Populate vector
float temp;
//I have tried to clear the stream with `data >> dummy` for
//both string and single char types below, but `data >> string`
//always clears too much, and `data >> char` doesn't seem to clear
//correctly either
//string dummy;
//char dummy;
vector<float> temps;
istringstream data(line);
while (data) {
//values between -100 and 100 are also considered corrupt
if (data >> temp && (temp <= 100 && temp >= -100)) {
temps.push_back(temp);
}
else if (!data.eof()) {
data.clear();
//trying to ignore all characters until I reach a space
//but that doesn't work correctly either
data.ignore(numeric_limits<streamsize>::max(), ' ');
//data >> dummy;
//cout << "Dummy: " << dummy << endl;
temps.push_back(-101.0);
}
}
//display resulting vector values
for(int i=0; i<temps.size(); ++i) {
cout << temps[i] << " ";
}
cout << endl;
}
My issue lies within the while (data) loop, specifically, inside the else if (!data.eof()) block. When data >> temp (type float) fails, the else if block runs. I clear the consequential failbit and attempt to ignore the remaining characters until the next space-delimiter comes up. However, a text file with a line like such:
a *a -100.1 100.1 a 10.a a 13-6s 12abc -12.a
produces problems. 13 and -6 are both processed as valid floats. I want to ignore the entire chunk of 13-6s, because these values are intended to be space-delimited.
What is the correct way to deal with this istringstream issue, where the characters are not being ignored the way I want?
I have been told by my professor that I can accomplish this with very basic STL techniques. He explicitly recommended to use stringstream as a way to parse floats. Is he in the wrong here?
Please comment for further clarity, if needed; I've been at this for quite some time now and would much appreciate some help.
Thank you!

This should do what you need.
#include <iostream>
#include <string>
#include <sstream>
int main() {
std::string temp;
// cin will write to temp with each space delimited entry
while (std::cin >> temp) {
std::stringstream s(temp);
float f;
// the first case checks if the actual write the float succeeds
// the second case checks if the entire stringstream has been read
if (!(s >> f) || !s.eof()) {
std::cout << temp << " failed!" << std::endl;
}
else {
std::cout << f << std::endl;
}
}
}
Apologies for not being able to answer your stringstream question but this solution should remove any necessity for that.
Note that input of 34.6 24.2 18.a 54.3 20.0 15.6 returns an output of:
34.6
24.2
18.a failed!
54.3
20
15.6
Edit: I added a case to the if statement to handle the stranger cases (i.e. 13-6s). It's a neat solution I found here.
Edit 2: I annotated some of the more complicated parts.

Try the following approach as it is shown in the demonstrative program.
#include <iostream>
#include <string>
#include <sstream>
#include <cstdlib>
#include <vector>
int main()
{
std::string line( "a *a -100.1 100.1 -100 a 10.a a 13-6s 100 12abc -12.a" );
std::istringstream is( line );
std::vector<float> values;
std::string item;
while ( is >> item )
{
const char *s = item.c_str();
char *tail;
float value = std::strtof( s, &tail );
if ( *tail == '\0' && -100.0f <= value && value <= 100.0f )
{
values.push_back( value );
}
}
for ( float value : values ) std::cout << value << ' ';
std::cout << std::endl;
return 0;
}
The program output is
-100 100
If to use this string
std::string line( "34.6 24.2 18.a 54.3 20.0 15.6" );
then the program output will be
34.6 24.2 54.3 20 15.6
Another approach is the following.
#include <iostream>
#include <string>
#include <sstream>
#include <limits>
#include <vector>
int main()
{
std::string line( "a *a -100.1 100.1 -100 a 10.a a 13-6s 100 12abc -12.a" );
// std::string line( "34.6 24.2 18.a 54.3 20.0 15.6" );
std::istringstream is( line );
std::vector<float> values;
while ( !is.eof() )
{
float value;
int c;
if ( not ( is >> value ) || ( ( c = is.get() ) != ' ' && c != std::char_traits<char>::eof() ) )
{
is.clear();
is.ignore( std::numeric_limits<std::streamsize>::max(), ' ' );
}
else if ( -100.0f <= value && value <= 100.0f )
{
values.push_back( value );
}
}
for ( float value : values ) std::cout << value << ' ';
std::cout << std::endl;
return 0;
}
The output will be the same as shown above.

Related

C++ Determining empty cells from reading in data

I'm reading in data from a csv file that has some columns ending before others, i.e.:
0.01 0.02 0.01
0.02 0.02
And I'm trying to figure out how to catch these empty locations and what to do with them. My current code looks like this:
#include <iostream>
#include <fstream>
#include <sstream>
int main(){
//Code that reads in the data, determines number of rows & columns
//Set up array the size of all the cells (including empty):
double *ary = new double[cols*rows]; //Array of pointers
double var;
std::string s;
int i = 0, j = 0;
while(getline(data,line))
{
std::istringstream iss(line); //Each line in a string
while(iss >> var) //Send cell data to placeholder
{
ary[i*cols+j] = var;
j+=1;
}
i+=1;
}
How can I determine if the cell is empty? I want to convert these to "NaN" somehow. Thank you!
You can do something like follows.
Get the inputs, line by line and using (std::getline(sstr, word, ' ')) you can set the deliminator to ' ' and the rest is checking weather the scanned word is empty or not.
If it's empty, we will set it to NaN(only once).
Input:
0.01 0.02 0.01
0.02 0.02
0.04 0.08
Here is the output:
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
int main()
{
std::fstream file("myfile.txt");
std::vector<std::string> vec;
if(file.is_open())
{
std::string line;
bool Skip = true;
while(std::getline(file, line))
{
std::stringstream sstr(line);
std::string word;
while (std::getline(sstr, word, ' '))
{
if(!word.empty())
vec.emplace_back(word);
else if(word.empty() && Skip)
{
vec.emplace_back("NaN");
Skip = false;
}
}
Skip = true;
}
file.close();
}
for(size_t i = 0; i < vec.size(); ++i)
{
std::cout << vec[i] << " ";
if((i+1)%3 ==0) std::cout << std::endl;
}
return 0;
}

Cannot Print All Integer Values

I would like to print integer values in a file by reading it.
The code:
int temp;
char* trainname;
trainname="dfg.txt";
ifstream trainfile;
trainfile.open(trainname);
if(!trainfile){
cout<<"Cannot open file!"<<'\n';
exit(1);
}
while(trainfile >> temp)
cout << temp << " ";
trainfile.close();
dfg.txt: 1 2 we er rf 5
output: 1 2
The problem is that it does not print 5.
Read to a temporary string first and then use std::stoi to try to parse an integer from it, and if it succeeds, output it:
std::string temp;
while(trainfile >> temp) {
try {
std::cout << std::stoi(temp) << " ";
}
catch(const std::invalid_argument&) {
// not a valid number
}
}
while(trainfile >> temp)
cout << temp << " ";
The above sets the failbit on trainfile on encountering any character that isn't whitespace or a digit. That terminates the loop. This is one reason I tend not to use formatted I/O that can fail on a input stream. I find it better to read text as text (not numbers) and then process the string that was just read. For example, see zenith's answer.
If you insist on doing everything from the input stream, you'll need an outer loop that clears the stream's failbit. For example,
while (! std::cin.eof())
{
while (std::cin >> temp)
{
std::cout << temp << " ";
}
std::cin.clear();
std::cin.ignore();
}
Given an input file containing 1 2 we er rf 5, the above will print 1 2 5. If the input file contains 1 2 abc345def 6, the above will print 1 2 345 6. Note that zenith's approach will print 1 2 6. Whether that 345 sandwiched between abc and def counts as an integer is up to you.
I'd recommend using zenith's solution over mine.
Update:
The above interprets abc345def as representing the integer 345. Both Zenith's solution and the above interpret 345def as representing the integer 345. To me, both abc345def and 345def should be rejected as representing an integer. So should 6.1 , but there's nothing wrong with 0x abc345def. There's nice tool in the C standard library, strtol, that nicely parses integers. It also indicates what made the parse stop. For a valid integer, it should stop at the end of the input string. With that,
#include <iostream>
#include < fstream>
#include <string>
#include <cstdlib>
int main ()
{
std::ifstream trainfile("dfg.txt");
if (!trainfile)
{
std::cerr << "Cannot open file!\n";
exit(1);
}
std::string s;
while(trainfile >> s)
{
char* end;
long num = std::strtol (s.data(), &end, 0);
if (!*end)
{
std::cout << num << " ";
}
}
trainfile.close();
std::cout << "\n";
}
string temp;
if( '0' <= temp[0] && temp[0]<='9' )
cout << temp << " ";
it will work i suppose.
Here is another way you can consider-
#include <iostream>
#include <sstream>
#include <fstream>
using namespace std;
int main()
{
ifstream trainname("dfg.txt",ios::in);
string temp;
getline(trainname,temp);
stringstream str;
str<<temp;
int extract_int;
while(getline(str, temp,' '))
{
if(stringstream(temp)>>extract_int)
cout<<extract_int<<" ";
}
return 0;
}
Or according to David Hammen's answer, you can solve it the following way-
#include <iostream>
#include <sstream>
#include <fstream>
using namespace std;
int main()
{
int temp;
char* trainname;
trainname="dfg.txt";
ifstream trainfile;
trainfile.open(trainname);
if(!trainfile){
cout<<"Cannot open file!"<<'\n';
exit(1);
}
while (!trainfile.eof())
{
while (trainfile>>temp)
cout<<temp<< " ";
trainfile.clear();
trainfile.ignore();
}
return 0;
}

reading data file into 2d array c++

I have a text file with 2 columns and many rows. each column is separated by spaces. i need to read them to a 2D array for further calculations.
my data file looks like
0.5 0.479425539
1 0.841470985
1.5 0.997494987
2 0.909297427
2.5 0.598472144
3 0.141120008
3.5 -0.350783228
4 -0.756802495
4.5 -0.977530118
5 -0.958924275
And my feeble attempt is
#include <iostream>
#include <fstream>
#include <string>
#include <conio.h>
#include <ctype.h>
using namespace std;
int main () {
char line,element;
std::ifstream myfile ("C:\\Users\\g\\Desktop\\test.txt");
if (myfile.is_open())
{
while ( myfile.good() )
{
getline(myfile,line);
cout << line<<endl;
_getch();
}
myfile.close();
}
else cout << "Unable to open file";
return 0;
}
The problem is I'm not able to read them correctly.... its either reading the whole line... if I specify the delimiter as 'space' then, its not reading the next row.
Pls point out whats wrong. and what should i do to store the data into 2d array for further calculations.
Thank you
#include <fstream>
#include <string>
#include <sstream>
#include <iostream>
#include <vector>
int main(int argc, char** argv) {
std::ifstream f(argv[1]);
std::string l;
std::vector<std::vector<double> > rows;
while(std::getline(f, l)) {
std::stringstream s(l);
double d1;
double d2;
if(s >> d1 >> d2) {
std::vector<double> row;
row.push_back(d1);
row.push_back(d2);
rows.push_back(row);
}
}
for(int i = 0; i < rows.size(); ++i)
std::cout << rows[i][0] << " " << rows[i][1] << '\n';
}
The last for loop shows how to use the values in the "array". The variable rows is strictly speaking not an array, but a vector of vectors. However, a vector is much safer than c-style arrays, and allows access to its elements using [].
[As I posted this I saw a very similar program posted as a response. I wrote mine independently.]
You can read the whole line into a std::string, then use std::istringstream to extract the values from the line.
A complete working program:
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
int main()
{
std::ifstream file("C:\\Users\\g\\Desktop\\test.txt");
std::string line;
// Read a line of input from the file
while (std::getline(file, line))
{
// `istringstream` behaves like a normal input stream
// but can be initialized from a string
std::istringstream iss(line);
float value;
// The input operator `>>` returns the stream
// And streams can be used as a boolean value
// A stream is "true" as long as everything is okay
while (iss >> value)
{
std::cout << "Value = " << value << '\t';
}
// Flush the standard output stream and print a newline
std::cout << std::endl;
}
}
Given the contents in the file being as in the question, the first three lines of output should be:
Value = 0.5 Value = 0.479425539
Value = 1 Value = 0.841470985
Value = 1.5 Value = 0.997494987
For a 2d-array, I would use a std::vector of std::array:
#include <vector>
#include <array>
...
std::vector<std::array<float, 2>> array;
...
float value1, value2;
if (iss >> value1 >> value2)
{
std::cout << "Values = " << value1 << ", " << value2;
array.emplace_back(std::array<int, 2>{{value1, value2}});
}
Now the first line values are array[0][0] and array[0][1], and the last lines values are array[array.size() - 1][0] and array[array.size() - 1][1].
As C++ has evolved over the years, below is a Modern C++ version.
It uses auto where possible
Uses std::pair to hold 2 values (A std::pair is a specific case of a std::tuple with two elements)
Does not close file (destructor does that at end of block)
Does not read line by line, as the stream uses <space> and <enter> as delimiters
The variables have meaningful names, so the program "reads" easily,
Uses a range for loop to output the data.
Doesn't bring the whole std namespace into the code - Why is “using namespace std” considered bad practice?
.
#include <fstream>
#include <iostream>
#include <vector>
#include <utility>
int main( int argc, char** argv )
{
if ( argc < 1 )
return -1;
const auto fileName = argv[ 1 ];
std::ifstream fileToRead( fileName );
typedef std::pair< double, double > DoublesPair;
std::vector< DoublesPair > rowsOfDoublesPair;
DoublesPair doublePairFromFile;
while ( fileToRead >> doublePairFromFile.first >> doublePairFromFile.second )
{
rowsOfDoublesPair.push_back( doublePairFromFile );
}
for ( const auto row : rowsOfDoublesPair )
std::cout << row.first << " " << row.second << '\n';
}

How do I read multiple data variables from line from input file C++?

I'm working on a program that reads in road data from an input file like this:
INTERSECTIONS:
1 0.5 Speedway and Campbell // intersection ID, safety rating, name
2 0.3 Park and Grant
3 0.1 Euclid and Grant
STREETS:
1 2 3 // intersection 1, intersection 2, distance in between
2 3 1
3 1 2
Each value in the table is separated by a tab (\t) character
I have to read this data into the appropriate variables specified by a graph.
I'm mostly looking for a simple answer: is it possible to use getline to read one line at a time and then separate the line into each bit of data? If so how would I do that?
Here is what I have so far in my main file:
#include "graph.h"
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
using namespace std;
vector <Vertex*> vertices;
vector <Edge*> edges;
int main (int argc, char *argv[]) {
if( argc != 4 )
{
std::cout << "\nUsage: " << argv[0] << " distanceInMiles startingIntersection streetMapGraphFile \n\n" << endl;
return -1;
}
ifstream mapfile ("streetMapGraphFile");
int count = 0;
int loc = 0;
Graph streetMap;
if (mapfile.is_open())
{
while ( mapfile.good() )
{
while ( count != 1 ) {
string line;
getline(mapfile,line);
if ( line == "INTERSECTIONS:" )
{
getline(mapfile,line);
}
else if ( line == "" )
{
count++;
break; // to avoid reading blank line line
}
stringstream ss(line);
ss >> streetMap.intersection->streetID >> streetMap.intersection->safetyIndex;
getline(ss, streetMap.intersection->name);
}
string line2;
getline(mapfile,line2);
if ( line2 == "STREETS:" )
{
getline(mapfile,line2);
}
// TODO: Read in the edges/streets here
stringstream ss2(line2);
ss2 >> streetMap.street->intersection1 >> streetMap.street->intersection2 >> streetMap.street->distance;
}
mapfile.close();
}
else { cerr << "Error: unable to open file" << endl; }
return 0;
}
I've changed my code to implement the stringstream on the line string, but when I debug step by step my compiler crashes after executing this line:
ss >> streetMap.intersection->streetID >> streetMap.intersection->safetyIndex;
The error reads "Unhandled exception at 0x0F592208 (msvcp110d.dll) in safejogger.exe: 0xC0000005: Access violation writing location 0xCCCCCCCC."
Yes it is possible. One way is to use a stringstream:
http://www.cplusplus.com/reference/sstream/stringstream/
Example:
#include <sstream>
#include <iostream>
#include <string>
using namespace std;
template <typename T>
void getVal(stringstream &ss, T &val)
{
string token;
getVal(ss, token);
stringstream ss2(token);
ss2>>val;
}
template <>
void getVal<string>(stringstream &ss, string &val)
{
getline(ss, val, '\t'); //Note the separator specification
}
int main(int argc, char** argv)
{
string line = "1\t2\t3";
stringstream ss(line);
int intersection1, intersection2, distance;
getVal(ss, intersection1);
getVal(ss, intersection2);
getVal(ss, distance);
cout<<"Distance was: "<<distance<<endl;
string line2 = "1\t0.5\t Speedway and Campbell";
stringstream ss2(line2);
int intersectionID;
float safetyRating;
string intersectionName;
getVal(ss2, intersectionID);
getVal(ss2, safetyRating);
getVal(ss2, intersectionName);
cout<<"Intersection name: ["<<intersectionName<<"]"<<endl;
return 0;
}

Write CSV file into vectors in C (continued)

Basically I have 14800x8 matrix that has been extracted from matlab as CSV file ("moves.mo"). I need to read this file into 14800 vectors with 8 values each.
Here is a few lines from the file:
1,2,3,4,-1,-3,-2,-4
1,2,3,5,-1,-3,-2,-5
1,2,3,6,-1,-3,-2,-6
1,2,3,7,-1,-3,-2,-7
1,2,3,8,-1,-3,-2,-8
1,2,3,9,-1,-3,-2,-9
I wrote the following code:
#include <iostream>
#include <fstream>
#include<stdio.h>
#include <string>
#include <istream>
#include <vector>
#include <sstream>
using namespace std;
int main()
{
std::fstream inputfile;
inputfile.open("moves.da");
std::vector< std::vector<int> > vectorsmovesList; //declare vector list
while (inputfile) {
std::string s;
if (!getline( inputfile, s )) break;
istringstream ss( s );
vector <int> recordmove;
while (ss)
{
if (!getline( ss, s, ',' )) break;
int recordedMoveInt = atoi(s.c_str());
recordmove.push_back( recordedMoveInt );
}
vectorsmovesList.push_back( recordmove );
}
if (!inputfile.eof())
{
cerr << "Fooey!\n";
}
It compiles but does not give me desirable output (i.e. just prints Fooey!) . I don't know why... This problem at this point is driving me insane.
Please help!
There are better ways to read integers in C++. For example:
std::string s;
if (!getline( inputfile, s )) break;
istringstream ss( s );
int recordedMove;
while (ss >> recordedMove)
{
recordmove.push_back(recordedMove);
// consume the commas between integers. note if there are no
// separating commas, you will lose some integers here.
char garbage;
ss >> garbage;
}
Also, you're not printing out your result anywhere. Here's how you would do it:
vector<vector<int> >::const_iterator ii;
for (ii = vectorsmovesList.begin(); ii != vectorsmovesList.end(); ++ii)
{
vector<int>::const_iterator jj;
for (jj = ii->begin(); jj != ii->end(); ++jj)
cout << *jj << ' ';
cout << endl;
}
Obviously, you'd do that after you've parsed and closed the CSV file.