C++ parse, fetch a variable number of integers from a string - c++

I have a set of strings which looks like
"4 7 14 0 2 blablabla"
"3 8 1 40 blablablablabla"
...
The first number N correspond to how many numbers will follow.
Basically, the format of a string is N+1 numbers, separated with a space, followed by an unknown number of irrelevant characters at the end that I don't need.
How can I get all the numbers in variables or a dynamic structure given that I don't know the number N in advance ?
In other words, I'd like something like:
sscanf(s, "%d %d %d %d",&n,&x,&y,&z);
which would work no matter how many numbers in the string.

The first thing would be to break up the input into lines, by using
getline to read it. This will greatly facilitate error recovery and
resynchronization in case of error. It will also facilitate parsing;
it's the strategy which should be adopted almost every time a newline in
the input is significant. After that, you use a std::istringstream to
parse the line. Something like:
std::vector<std::vector<int> > data;
std::string line;
while ( std::getline( input, line ) ) {
std::istringstream l( line );
int iCount;
l >> iCount;
if ( !l || iCount < 0 ) {
// format error: line doesn't start with an int.
} else {
std::vector<int> lineData;
int value;
while ( lineData.size() != iCount && l >> value ) {
lineData.push_back( value ) ;
}
if ( lineData.size() == iCount ) {
data.push_back( lineData );
} else {
// format error: line didn't contain the correct
// number of ints
}
}
}

int input;
std::vector<int> ints;
while(std::cin >> input) //read as long as there is integer
ints.push_back(input);
std::cin.clear(); //clear the error flag
//read the remaining input which most certainly is non-integer

std::string s = "3 54 -4 42 fdsvadsdsberwte";
std::istringstream source(s);
std::vector<int> ints;
int num = 0;
int temp = 0;
if (source >> num) // read the first number and if it succeeds, read the rest
{
while(source >> temp) ints.push_back(temp);
// Here, I'd compare the size of the vector with what was
// expected (num) and act accordingly.
}
else
{
// format error
}

You could do it something like this:
std::string buffer;
while(std::getline(in, buffer)) { // read a line
std::istringstream str(buffer); // put line in a stringstream for parsing
int count;
str >> count; // read first number
std::vector<int> numbers(count); // reserve space for other numbers
for(int i = 0; i < count; i++) { // read other numbers
str >> numbers[i];
}
}

Initialize an istringstream with your string, and read from it:
std::istringstream ss(s);
int N;
ss >> N;
std::vector<int> a(N); //int* a = new int[N];
for (int i=0;i<N;i++)
ss >> a[i];

You can use dynamic array and a linked list, of dynamic array type. After reading a line initialize the array using number N and insert the numbers sequentially on each index. Insert the node containing line data to linked list.
Pseudo code:
int *lineNumbers;
lineNumbers = new int[N];
List<int*> data;
data.insert(lineNumbers);

Related

String values become 0 after using getline from .csv into an array C++

I'm reading a csv file into c++ to make an multiple parallel arrays and print reports from it. I'm able to cout the strings, no problem, but when I try to create indices, conditions, or translate into int, the strings return no values. There are no characters when I try to atoi, so that is not the issue. I've looked everywhere and can't find any other similar questions. The logic of my code is also not the issue because it works when I populate the tempArray2 manually. Also, I'm a first semester student, so there's going to be some kludge in my code. Does the getline eliminate the value of the string?
(Because this was flagged as answered: This is not a duplicate question, I am not trying to parse the csv into vectors, I'm using parallel arrays and this worked for generating my first report because those values were not strings. Using a parser someone else programed would cause me to fail this assignment and doesn't answer my question why values become 0.)
Here's a snippet of the .csv; the lines are not double spaced on the notepad.
"LOCATION","INDICATOR","SUBJECT","MEASURE","FREQUENCY","TIME","Value","Flag Codes"
"GBR","FERTILITY","TOT","CHD_WOMAN","A","2019",1.63,
"USA","FERTILITY","TOT","CHD_WOMAN","A","1970",2.48,
"USA","FERTILITY","TOT","CHD_WOMAN","A","1971",2.27,
Here's the readFile function. You can see the comment where I tried to atoi the year column (replacing yr[x] with temp like in column 7, which works) and it returns 0 value, even though that column clearly has only ints in the string.
bool ReadFile(string loc[], string yr[], float rates[])
{
ifstream input{FILENAME.c_str()};
if (!input)
{
return false;
}
//init trash and temp vars
string trash, temp;
//trash header line
for (int i{ 0 }; i < 1; ++i)
{
getline(input, trash);
}
for (int x{ 0 }; x < SIZE; ++x)
{
getline(input, loc[x], ',');//read column 1 country
getline(input, trash, ','); // column 2 trash
getline(input, trash, ','); // column 3 trash
getline(input, trash, ','); // column 4 trash
getline(input, trash, ','); // column 5 trash
getline(input, yr[x], ',');// read column 6 year
//yr[x] = atoi(temp.c_str());// would always return value 0 even though no char interfering
getline(input, temp, ',');//read column 7 rates
rates[x] = atof(temp.c_str());
cout << yr[x];
cout << loc[x];
cout << rates[x];
}
return true;
}
And the analyze function, where the issue also occurs in the tempArray2 block. It cannot read "USA" for the boolean, but works if I set it to !=, it will also include indices that clearly have "USA". The first tempArray works as expected.
void Analyze(string loc[], string yr[], float rates[], FertilityResults& result)
{
// array for highest and lowest fertrates
float tempArray[SIZE];
for (int i{ 0 }; i < SIZE; ++i)
{
tempArray[i] = rates[i];
}
result.highestRate = 0;
result.lowestRate = 20;
for (int i{ 1 }; i < SIZE; ++i)
{
if (tempArray[i] >= result.highestRate)
{
result.highestRate = tempArray[i];
result.highestRateIndex = i;
}
else if (tempArray[i] > 0 && tempArray[i] < result.lowestRate)
{
result.lowestRate = tempArray[i];
result.lowestRateIndex = i;
}
}
//2nd array to retrieve USA data
string tempArray2[SIZE];
for (int i{ 0 }; i < SIZE; ++i)
{
tempArray2[i] = loc[i];
//cout << tempArray2[i];
if (tempArray2[i] == "USA")
{
cout << "hi";
result.usaIndex = i;
cout <<result.usaIndex<<endl;
}
}
}
Please let me know if you need anything else or if it runs on your terminal as is somehow.
Thanks, this is my final project and the first time I've had to ask for help.

User input to matrix in C++

I have trouble to read in an input from user and convert them into matrix for calculation. For example, with the input = {1 2 3 / 4 5 6}, the program should read in the matrix in the form of
1 2 3
4 5 6
which have 3 cols and 2 rows. What i got so far which does not seem to work:
input.replace(input.begin(), input.end(), '/', ' ');
stringstream ss(input);
string token;
while (getline(ss, token, ' '))
{
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
int tok = atoi(token.c_str());
(*matrix).setElement(i, j, tok);
}
}
}
So what I'm trying to do is to break the input into token and store them into the matrix using the setElement function which take the number of row, column and the variable that user want to store. What wrong with this code is that the variable of tok doesnt seem to change and keep stuck in 0. Assuming that row and col are knows.
Thanks so much for any help.
Although many simple ways exist to solve the specific problem (and other answer have various good suggestions) let me try to give a more general view of the problem of "formatted input".
There are essentially three kind of problems, here:
at low level you have to do a string to number conversion
at a higher level you have to parse a composite format (understanding rows and line separation)
finally you also have to understand the size of the compound (how many rows and cols?)
this 3 things are not fully independent and the last is needed to know how to store elements (how do you size the matrix?)
Finally there is a 4th problem (that is spread all other the other 3): what to do if the input is "wrong".
These kind of problem are typically afforded in two opposite ways:
Read the data as they come, recognize if the format is matched, and dynamically grow the data structure that have to contain them or...
Read all the data as once as they are (textual form), then analyze the text to figure out how many elements it has, then isolate the "chunks" and do the conversions.
Point 2. requires good string manipulations, but also requires the ability to know how the input is long (what happens if one of the separating spaces is a new-line? the idea the everything is got with a getline fails in those cases)
Point 1 requires a Matrix class that is capable to grow as you read or a temporary dynamic structure (like and std container) in which you can place what you read before sending it into the appropriate place.
Since I don't know how your matrix works, let me keep a temporary vector and counters to store lines.
#include <vector>
#include <iostream>
#include <cassert>
class readmatrix
{
std::vector<int> data; //storage
size_t rows, cols; //the counted rows and columns
size_t col; //the counting cols in a current row
Matrix& mtx; //refer to the matrix that has to be read
public:
// just keep the reference to the destination
readmatrix(Matrix& m) :data(), rows(), cols(), cols(), mtx(m)
{}
// make this class a istream-->istream functor and let it be usable as a stream
// manipulator: input >> readmatrix(yourmatrix)
std::istream& operator()(std::istream& s)
{
if(s) //if we can read
{
char c=0:
s >> c; //trim spaces and get a char.
if(c!='{') //not an open brace
{ s.setstate(s.failbit); return s; } //report the format failure
while(s) //loop on rows (will break when the '}' will be found)
{
col=0;
while(s) //loop on cols (will break when the '/' or '}' will be found)
{
c=0; s >> c;
if(c=='/' || c=='}') //row finished?
{
if(!cols) cols=col; //got first row length
else if(cols != col) //it appears rows have different length
{ s.setstate(s.failbit); return s; } //report the format failure
if(c!='/') s.unget(); //push the char back for later
break; //row finished
}
s.unget(); //pushthe "not /" char back
int x; s >> x; //get an integer
if(!s) return s; //failed to read an integer!
++col; data.push_back(x); //save the read data
}
++rows; //got an entire row
c=0; s >> c;
if(c == '}') break; //finished the rows
else s.unget(); //push back the char: next row begin
}
}
//now, if read was successful,
// we can dispatch the data into the final destination
if(s)
{
mtx.setsize(rows,cols); // I assume you can set the matrix size this way
auto it = data.begin(); //will scan the inner vector
for(size_t r=0; r<rows; ++r) for(size_t c=0; c<cols; ++c, ++it)
mtx(r,c) = *it; //place the data
assert(it == data.end()); //this must be true if counting have gone right
}
return s;
}
};
Now you can read the matrix as
input >> readmatrix(matrix);
You will notice at this point that there are certain recurring patterns in the code: this is typical in one-pass parses, and those patterns can be grouped to form sub-parsers. If you do it generically you -in fact- will rewrite boost::spirit.
Of course some adaption can be done depending on how your matrix works (has it fixed sizes??), or what to do if rows sizes don't match (partial column filling ??)
You can even add a formatted input operator like
std::istream& operator>>(std::istream& s, Matrix& m)
{ return s >> readmatrix(m); }
so that you can just do
input >> matrix;
You are trying to operate on each cell of the matrix for each char read in the input!
You have to take one char for each cell, not multiple.
Splitting a string in tokens can be done by using the following function.
Please don't be shocked that the following code isn't runnable, this is due to the missing matrix class.
Try the following:
#include <iostream>
#include <string>
#include <sstream>
#include <algorithm>
#include <iterator>
using namespace std;
void split(const string& str, char delimiter, vector<string>& result) {
string::size_type i = 0;
string::size_type delimOcc = str.find(delimiter);
while (delimOcc != string::npos) {
result.push_back(str.substr(i, delimOcc-i));
i = ++delimOcc;
delimOcc = str.find(delimiter, delimOcc);
if (delimOcc == string::npos) {
result.push_back(str.substr(i, str.length()));
}
}
}
int main()
{
std::string input = "1 2 3 / 4 5 6";
vector<string> rows;
split(input, '/', rows);
for(int i = 0; i < rows.size(); i++) {
vector<string> cols;
split(rows[i], ' ', cols);
for(int j = 0; j < cols.size(); j++) {
if(cols[j][0] != '\0'){
int tok = stoi(cols[j]);
(*matrix).setElement(i, j, tok);
cout << tok << " - " << i << " - " << j << endl;
}
else {
if(j == 0) j--;
}
}
}
return 0;
}
If you know the size of the matrix on forehand you actually don't need getline, you should read int by int. (untested code)
input.replace(input.begin(), input.end(), '/', '\n');
stringstream ss(input);
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
int tok;
ss >> tok;
(*matrix).setElement(i, j, tok);
}
}

Reading list of integers into an Array C++

I am working on a program in C++ that will read integers from a file, then pass them to a function that checks for a Subset Sum.
The file is formatted like so:
number of cases n
sum for case 1
list of integers separated by a space
sum for case
list of integers separated by a space
sum for case n
list of integers separated by a space
My problem now lies in how to read the list of integers into an array to be passed to my function.
This is my main so far:
fstream infile("subset.txt");
if(infile.is_open()){
int numCases, num;
infile >> numCases;
while(infile >> num){
for(int i = 0; i < numCases; i++)
{
int sum;
int set[30];
num >> sum;
for(int i = 0; i < 30; i++)
{
if(num == '\n')
{
sum[i] = -1
}
else
{
num << sum[i]
}
}
int n = sizeof(set)/sizeof(set[0]);
if(subsetSum(set, n, sum) == true)
printf("True");
else
printf("False");
}
}
}
else
printf("File did not open correctly.");
return 0;
Any help you guys can give me would be greatly appreciated.
Yes, this is for an assignment, so if you would rather just give me hints that would be appreciated as well. The assignment is for the algorithm and I have that working, I just need a hand with the I/O.
I would read the line containing the list of numbers using std::getline, then use an istringstream to parse numbers out of that string.
I'd also use a std::vector instead of an array to hold the numbers. For the actual parsing, I'd probably use a pair of std::istream_iterators, so the code would look something like this:
while (infile >> sum) {
std::getline(infile, line);
std::istringstream buffer(line);
std::vector<int> numbers{std::istream_iterator<int>(buffer),
std::istream_iterator<int>()};
std::cout << std::boolalpha << subsetSum(numbers, sum);
}

How can I transfer a text file to array 2D in C++?

How can i transfer a text file(.txt) to array 2D in c++ and this is my source code
fstream fin('textfile.txt', ios::in);
int matrix[n][m]; // n is the number of rows and m is the number of columns
for(int i = 0;i < n; i++){
for(int j = 0; j<m; j++){
fin>>matrix[i][j];
}
}
but how can i detemine n and m for do this,i need your help and your advice, please Join us your perspectives
This solution requires C++11+
If there is no n & m in the file, you must assume that the layout is also in 2D
One Two Three
Four Five Six
Warning:: Untested code.
std::stringstream res;
std::string wordUp;
std::vector<std::string> str;
// the matrix, vector of vector of strings.
std::vector<std::vector<std::string>> matrix;
fstream fin('textfile.txt', ios::in);
int lines = 0;
int words = 0;
// read the file line by line using `getline`
for (std::string line; std::getline(fin, line); ) {
++lines;
// use stringstream to count the number of words (m).
res.str(line); // assign line to res. might also need some reset of good().
while (res.good()) {
res >> wordUp;
str.push_back(wordUp);
++words;
}
matrix.push_back(str);
str.erase(str.begin());
}
So u mean u want to read a file and copy contents to char Matrix[][]??, you can use while loop to read characters, and split every 1024 bytes(1 kb) by lines, i mean do this:
#include <fstream.h>
int main()
{
int n=0, m=0, MAX_LINES=1025, i=0, j=0;
char character, Matrix[1024][1025];
fstream file;
file.open("file.txt", ios::in);
while (file.get(character))// loop executes until the get() function is able to read contents or characters from the file
{
Matrix[n][m]=character; // copy the content of character to matrix[n][m], here n is used to work as lines and m as normal arrays.
m++; // finished copying to matrix[n][m] then m++ else the program will overwrite the contents to the same array.
If (m>=1024)// if string[n][m] reached the limit which is 1024.
{
Matrix[n][m]='\0'; //termimate that line
m=0;// start with a new column
if (n<MAX_LINES)// if n is less than 1024 then
n++;// write to a next line because m can support only 1024 chars.
}
}
Matrix[n][m]='\0';// this will terminate the whole string not just one line.
file.close();
for (i=0; i<1025; i++)
{
for (j=0; j<=1024 || Matrix[i][j]!='\0'; j++)
cout<<Matrix[i][j];
}
return 0;
}
This code will read 1024×1024 chars, but if the txt file is less than 1024(m) characters, the while loop will be exited and Matrix[n][m]='\0'; statement is executed.
EDIT: As asked by David i have written the whole code with main() sorry bro i forget, the bug in the code was the variables n and m were intialised to 1025 and 1024 so the program skips writing to Matrix as the Matrix[1024][1025] cannot store more characters... I think this would help, ok bro...

c++ get multiple lines

I need a way to read the lines a user has pasted in the console. The user pastes it in this fashion:
1st line: n - number of lines except this one
2nd - nth: a string object
If I read it with cin, it reads the first line, exits the program, and the next lines is placed in the console input. With scanf I get similar results.
string s[100];
int N = 0;
scanf("%i", N);
for (int i = 0; i < N; i++)
{
scanf("%s", s);
}
It would be better if you used a std::vector<std::string> and use std::getline to extract the lines:
std::vector<std::string> lines;
std::string line;
while (std::getline(std::cin >> std::ws, line))
{
if (!line.empty())
lines.push_back(line);
}
getline() will do the trick for you. Try this:
string lines[100];
int number = 0;
cin >> number;
for (int idx = 0; idx != number; ++idx)
{
getline(cin, lines[idx]);
}
Note that you cannot read more than 100 lines this way. If you want to dynamically allocate an array of lines of size n, you can use the new operator.