Reputation: 95
I am writing a program that reads data from a file.
the .txt file looks like this:
Text, numbers, : 5,3,5
Text, numbers, : 1,3,7,8
I was successful in extracting the "Text" and "Numbers", However when I came across the numbers after the : "5,3,5", I was really stuck.
I need to change these numbers to ints and add them to a vector of int, so I got rid of the commas, then tried using stoi to convert them to ints, however, stoi was only "extracting" the first number, in this case, only 5 and 1, this is what I've tried:
while(getline(file, line)){
stringstream ss(line);
getline(ss, text, ',');
getline (ss, nums, ':');
getline (ss, numList, ',' );
replace(numList.begin(), numList.end(), ',' , ' ');
vec.push_back(stoi(numList));
randomStruct str = {text, nums, numList};
randomStructVec.push_back(str);
}
I need the output to look like this when printing the elements of the vector:
5 3 5
1 3 7 8
what I'm getting is :
5
1
and other times I get duplicate numbers as well: 5
1111
or
5555
11
I need a way to make the stoi function convert all the numbers on that one line of string to ints, and store them in a vec of ints.
Any help, would be greatly appreciated.
Upvotes: 6
Views: 756
Reputation: 1552
Check out my solution at How do I tokenize a string that uses the String Toolkit Library
Here is a paired down version for your case:
#include <iostream>
#include <vector>
#include <string>
#include <strtk.hpp> //String Toolkit Library
const char *whitespace = " \t\r\n\f";
const char *whitespace_and_punctuation = " \t\r\n\f;,=";
int main()
{
// parsing a string into a vector of integers with separators
// of spaces and punctuation
std::string s("3; 4, 4, 8,-1");
std::vector<int> values;
if( strtk::parse( s, whitespace_and_punctuation, values ) )
{
for(size_t i = 0; i < values.size(); ++i )
std::cout << values[i] << std::endl;
}
return 0;
}
You will notice the conversion of the values into a vector of integers. The library is header only. The library is VERY fast and can handle most anything you need to do with a string and parsing.
Upvotes: 6
Reputation: 493
There is too main problem in your code.
First of all getline (ss, numList, ',' );
will stop on the first value of the list. In fact, when your list is 5,3,5
, getline (ss, numList, ',');
will read 5
then ,
so it will stop. At this point, numValue == "5"
This is quite simple to fix : Just remove the delimiter char, so getline(ss, numList);
. Using this, numValue == "5,3,5"
Alright, now you have all your value. You replace ','
by ' '
in order to separate your numbers. Good, numList = "5 3 5"
.
And then is your second error : vec.push_back(stoi(numList));
. stoi(numList)
return an int and is not able to get through space characters. So it will only convert the first 5
and return it. You will never get the other numbers, as you don't even do a loop.
Here is my solution : convert your string to a stringstream and use >>
operator
std::stringstream numStream(numList);
int value;
while(numList >> value)
vec.push_back(value);
So we end up with your final code (I removed std
s, as it seems that you wrote using namespace std
somewhere in your code)
struct randomStruct
{
string txt,
string nb,
vector<int> data
}
// -------
while(getline(file, line)){
stringstream ss(line);
getline(ss, text, ',');
getline (ss, nums, ':');
getline (ss, numList);
replace(numList.begin(), numList.end(), ',' , ' ');
stringstream numStream(numList);
int value;
while(numStream >> value)
vec.push_back(value);
randomStruct str = {text, nums, vec};
randomStructVec.push_back(str);
vec.clear();
}
// Accessing and printing data
for (auto str : randomStructVec)
{
for (auto i : str.data)
{
cout << i << " ";
}
cout << endl;
}
Upvotes: 1
Reputation: 1460
Use this function stoi_()
in this function, I am converting a string into a number if that string contains the characters in range 0-9
otherwise create a new string and repeat this process until you reach the end of string. To handle negative numbers you have to add one more condition.
vector<int> stoi_(string s){
vector<int>ans;
int i = 0;
int n =s.length();
while(i<n){
string temp = ""; // current number
if(s[i]=='-' && (i+1<n && (s[i+1]>='0' && s[i+1]<='9'))){ // handle -ve numbers
temp = temp + s[i];
i++;
}
while(i<n && s[i]>='0' && s[i]<='9'){ // if current character is number append it into cur number
temp = temp + s[i];
i++;
}
if(temp.length()>0){
ans.push_back(stoi(temp)); // here using stoi() for simplicity
}
else{
i++;
}
}
return ans;
}
Upvotes: 1