Okay I read that if we have a string s =" 1 2 3"
we can do :
istringstream iss(s);
int a;
int b;
int c;
iss >> a >> b >> c;
Lets say we have a text file with the following :
test1
100 ms
test2
200 ms
test3
300 ms
ifstream in ("test.txt")
string s;
while (getline(in, s))
{
// I want to store the integers only to a b and c, How ?
}
1) You can rely on succesful convertions to int:
int value;
std::string buffer;
while(std::getline(iss, buffer,' '))
{
if(std::istringstream(buffer) >> value)
{
std::cout << value << std::endl;
}
}
2) or just skip over unnecessary data:
int value;
std::string buffer;
while(iss >> buffer)
{
iss >> value >> buffer;
std::cout << value << std::endl;
}
If you know the pattern of the details in the text file, you could parse through all the details, but only store the int values. For example:
ifstream in ("test.txt")
string s;
while (getline(in, s))
{
getline(in,s); //read the line after 'test'.
string temp;
istringstream strm(s);
s >> temp;
int a = stoi(temp) // assuming you are using C++11. Else, atoi(temp.c_str())
s >> temp;
getline(in,s); // for the line with blank space
}
This above code is still somewhat of a inelegant hack. What you could do besides this is use random file operations in C++. They allow you to move your pointer for reading data from a file. Refer to this link for more information: http://www.learncpp.com/cpp-tutorial/137-random-file-io/
PS: I haven't run this code on my system, but I guess it should work. The second method works for sure as I have used it before.
Related
Is there a way to "dump" a value read using a stream without reading it into a dummy variable?
For example, if I have a file which contains two strings and an integer, e.g., "foo.txt" looks like this:
foo bar 6
foofoo barbar 8
Is it possible to do something like this:
std::string str;
int i;
std::ifstream file("foo.txt");
file >> str >> nullptr >> i;
and have str = "foo" and i = 6 afterwards?
There is std::basic_istream::ignore but it is pretty much useless because:
It can only skip one particular delimiter character, not a character class (e.g. any whitespace).
It needs to be invoked multiple times to skip a word.
You can write a function ignore_word(std::istream& s):
std::istream& ignore_word(std::istream& s) {
while(s && std::isspace(s.peek()))
s.get();
while(s && !std::isspace(s.peek()))
s.get();
return s;
}
int main() {
std::istringstream s("foo bar 6");
std::string foo;
int i;
s >> foo;
ignore_word(s);
s >> i;
std::cout << foo << ' ' << i << '\n';
}
I have a file with following lines:
51:HD L80 Phone:78
22:Nokia Phone:91
I need to split these into 3 separate variables
(int, string, int)
int id = line[0]
string phoneName = line[1]
int price = line [2]
I have tried many solutions for example:
std::ifstream filein("records");
for (std::string line; std::getline(filein, line); )
{
// std::cout << line << std::endl;
std::istringstream iss (line);
std::string word;
std::vector<string> tempString;
while(std::getline(iss,word,',')){
tempString.push_back(word);
// std::cout << word << "\n";
}
However in this example I do get the values but they are coming in a stream and not in one go. I do not want to save them into vector (no other way to store the incoming values) but call a function immediately after getting all the 3 values.
SOLUTION
This is a modification of the accepted answer:
`for (std::string line; std::getline(filein, line); )
{
// std::cout << line << std::endl;
std::istringstream iss (line);
for (int stockID; iss >> stockID; )
{
char eater;
iss >> eater; // this gets rid of the : after reading the first int
std::string stockName;
std::getline(iss, stockName, ':'); // reads to the next :, tosses it out and stores the rest in word
std::string catagory;
std::getline(iss, catagory, ':'); // reads to the next :, tosses it out and stores the rest in word
std::string subCatagory;
std::getline(iss, subCatagory, ':');
int stockPrice;
iss >> stockPrice;
iss >> eater; // this gets rid of the : after reading the first int
int stockQTY;
iss >> stockQTY; // get the last int
// iss >> eater;
// std::cout << stockName << "\n";
Record recordd = Record(stockID,stockName,catagory,subCatagory,stockPrice,stockQTY);
record.push_back(recordd);
}
}`
for when text file contains:
51:HD L80 Phone:Mobile:Samsung:480:40
22:Nokia Phone:Mobile:Nokia:380:200
There is no reason to use a std::stringstream here if you know you are going to have exactly 3 columns in every row. Instead you can read those values directly from the file, store them in temporaries, and then call the function with those temporary variables.
for (int a; filein >> a; )
{
char eater;
filein >> eater; // this gets rid of the : after reading the first int
std::string word;
std::getline(filein, word, ':'); // reads to the next :, tosses it out and stores the rest in word
int b;
filein >> b; // get the last int
function_to_call(a, word, b);
}
You can find different ways to split a string here:
https://www.fluentcpp.com/2017/04/21/how-to-split-a-string-in-c/
Example:
std::vector<std::string> split(const std::string& s, char delimiter)
{
std::vector<std::string> tokens;
std::string token;
std::istringstream tokenStream(s);
while (std::getline(tokenStream, token, delimiter))
{
tokens.push_back(token);
}
return tokens;
}
How to read integers from the following text file containing symbols, numbers and maybe alphabets?
I have the following text file
#
100:20 ;
20:40 ;
#
#
50:30 ;
#
#
10:21:37 ;
51:23 ;
22:44 ;
#
I have tried the following codes :
int main()
{
std::ifstream myfile("10.txt", std::ios_base::in);
int a;
while (myfile >> a)
{
std::cout<< a;
}
return 0;
}
and
void main()
{
std::ifstream myfile("10.txt", std::ios_base::in);
std::string line;
while (std::getline(infile, line))
{
std::istringstream iss(line);
int n;
while (iss >> n)
{
std::cout << n ;
}
}
}
All I get is a garbage value of int variable (or the initial value if I initialize it )
How to solve this?
You can try splitting each line into separate tokens delimited by the colon character:
int main()
{
std::ifstream myfile("10.txt", std::ios_base::in);
std::string line;
while (std::getline(myfile, line))
{
std::istringstream iss(line);
std::string token;
while (std::getline(iss, token, ':'))
{
std::istringstream tss(token);
int n;
while (tss >> n)
{
std::cout << n << std::endl;
}
}
}
return 0;
}
This should print:
100
20
20
40
50
30
10
21
37
51
23
22
44
As per this comment, I recommend a more robust parsing algorithm that respects the unique structure of your files.
Try skipping bad character one after another
Something like:
while (!in.eof())
{
int a;
in >> a;
if (!in) // not an int
{
in.clear(); // clear error status
in.ignore(1); // skip one char at input
}
else
{
cout << a;
}
}
I am facing a problem how to read space separated data from input stream.
Lets say we need to input J 123 7 3 M. First is letter and last is letter. The rest is int.
vector<int> ints;
vector<char> chars;
stringstream ss;
...
cin >> c
chars.push_back(c);
ss << c;
cin >> i;
while(ss << i) {
ints.push_back(i);
}
...
But this code does not resolve the problem. I tried lots of combinations and still nothing.
I was thinking that I could read everything as char and then convert it to int.
I know that there are similar questions to that but in my case I would like to solve that without string and not dynami arrays (may be dynamic array but without set length).
EDIT
I managed to read such stram by:
char first, last;
int i;
std::cin >> first;
std::cout << first;
while(std::cin >> i) {
std::cout << i;
}
std::cin >> last;
std::cout << last;
But there is one problem:
writing "F 1 23 2 2 W" displays F12322#. Don't know why there is "#" at the end.
Any thoughts?
EDIT2:
std::cin.clear();
after while loop solves the problem.
In order to organize and add your data you could create a small struct which with an operator>> for example (ideone):
struct line{
char f1,f5; // give them meaningful names
int f2,f3,f4;
friend std::istream &operator>>(std::istream &is, line &l) {
is >> l.f1;
is >> l.f2;
is >> l.f3;
is >> l.f4;
is >> l.f5;
return is;
}
};
int main() {
string input = "J 123 7 3 M\nK 123 7 3 E\nH 16 89 3 M";
stringstream ss(input);
vector<line> v;
line current;
while(ss >> current){
v.push_back(current);
}
for (auto &val: v){
cout<< val.f1 << endl;
}
return 0;
}
Each time you read something you can do whatever you'd like with the current line. If each lien does not have a specific meaning you could just do a
while(ss>>f1>>f2>>f3>>f4>>f5){
// do stuff with fields
}
Where ss is a stringstream but it could all so be cin.
If you know the number of elements and its type then you can use the following code for
#include<vector>
#include<iostream>
using namespace std;
int main()
{
int i;
char c;
vector<int> ints;
vector<char> chars;
cin>>c;
chars.push_back(c);
for(int j=0;j<3;j++){
cin>>i;
ints.push_back(i);
}
cin>>c;
chars.push_back(c);
}
I am trying to read in a text file that has a name and age on each line such as this
Tom
55
Bob
12
Tim
66
I then need to pass it to a function which takes in a string and an int such as:
sortDLL.Insert(name, age);
However, I am unsure how to do this. I tested it out with the following and it works (bypassing the text file):
string tom = "tom";
string bob = "bob";
string tim = "tim";
int a = 55;
int b = 12;
int c = 66;
sortDLL.Insert(tom, a);
sortDLL.Insert(bob, b);
sortDLL.Insert(tim, c);
But when I try to read in the text file and send it, the program doesn't run properly. This is what I am currently trying, and I have messed around with a few other things, but have had no luck:
ifstream infile ("names.txt");
while(getline(infile, line));
{
istringstream ss(line);
if (ss >> name)
cin >> name;
else if (ss >> wt)
cin >> wt;
sortDLL.Insert(name, wt);
}
infile.close();
Like always, any help to get this to work would be greatly appreciated, thanks!
I think the correct code should look like this. Remember you have to read 2 line per 1 insert.
while(getline(infile, line))
{
stringstream ss(line);
ss >> wt;
if(ss.fail()) {
name = line;
continue;
}
else {
// cout << name << ":" << wt << endl;
sortDLL.Insert(name, wt);
}
}