Stringstream doesn't lose data when extracted - c++

I want to create a file which stores some digits, later to be extracted into an array.
#include <vector>
#include <fstream>
#include <iostream>
#include <stringstream>
//for setw()
#include <iomanip>
std::vector<int> getData()
{
using namespace std;
//For the sake of this question simplicity
//I won't validate the data
//And the text file will contain these 10 digits:
//1234567890
ifstream in_file("altnum.txt");
//The vector which holds the results extracted from in_file
vector<int> out;
//It looks like C++ doesn't support extracting data
//from file to stringstream directly
//So i have to use a string as a middleman
stringstream ss;
string str;
//Extract digits from the file until there's no more
while (!in_file.eof())
{
/*
Here, every block of 4 digits is read
and then stored as one independent element
*/
int element;
in_file >> setw(4) >> str;
cout<<str<<"\n";
ss << str;
cout<<ss.str()<<"\n";
ss >> element;
cout<<element<<"\n";
out.push_back(element);
}
//Tell me, program, what have you got for my array?
for (auto &o : out)
cout << o << ' ';
in_file.close();
return out;
}
When i run the snippet of code above, i get the following numbers:
1234 1234 1234
while
1234 5678 90
is expected.
And then i found out (by cout-ing each variable to the screen) that the stringstream ss does not release its content when extracted to 'element'
But why is that? I thought that like cin stream, after the extraction, the stream would pop data out of it? Did i miss anything extremely important?

Related

Unknown number of strings (in letters) in the input

I want to write a program in which the names of n different chemical elements are read in the same line in the input (where 1 ≤ n ≤ 17 and n is also read in the input) (the names are made apart by a space). The names of the chemical elements should be stored in different strings for further uses.
As n is unknown, I don't know how to make something like an "array of strings". Of course I should not make 17 different strings st1,st2,st3,... :D.
Can you please help me? Any help will be high appreciated and they will help me a lot.
Thank you in advance.
It sounds like you want to read in a line and split it with spaces. Try something such as this:
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
int main()
{
std::string input;
std::getline(std::cin, input); // takes one line, stops when enter is pressed
std::stringstream ss(input); // makes a stream using the string
std::vector<std::string> strings;
while (ss >> input) { // while there's data left in the stream, store it in a new string and add it to the vector of strings
strings.push_back(input);
}
for (std::string s : strings) {
std::cout << "string: " << s << std::endl;
}
}
You give input such as H He Li, terminated by hitting enter, and the strings are stored in strings (printed in last loop for demonstration).
Edit:
I now see that you want to read the number n in the input, too. In this case, you don't need the stringstream solution. You can do this instead:
int main()
{
int amount;
std::cin >> amount; // read in the amount
std::vector<std::string> strings;
for (int i = 0; i < amount; i++) {
std::string s;
std::cin >> s; // read in the nth string
strings.push_back(s); // add it to the vector
}
for (std::string s : strings) {
std::cout << "string: " << s << std::endl;
}
}
And pass input such as 3 H He Li.

Reading a text file and storing data into multiple arrays C++

I am trying to read a database file (as txt) where I want to skip empty lines and skip the column header line within the file and store each record as an array. I would like to take stop_id and find the stop_name appropriately. i.e.
If i say give me stop 17, the program will get "Jackson & Kolmar".
The file format is as follows:
17,17,"Jackson & Kolmar","Jackson & Kolmar, Eastbound, Southeast Corner",41.87685748,-87.73934698,0,,1
18,18,"Jackson & Kilbourn","Jackson & Kilbourn, Eastbound, Southeast Corner",41.87688572,-87.73761421,0,,1
19,19,"Jackson & Kostner","Jackson & Kostner, Eastbound, Southeast Corner",41.87691497,-87.73515882,0,,1
So far I am able to get the stop_id values but now I want to get the stop name values and am fairly new to c++ string manipulation
mycode.cpp
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
using namespace std;
int main()
{
string filename;
filename = "test.txt";
string data;
ifstream infile(filename.c_str());
while(!infile.eof())
{
getline(infile,line);
int comma = line.find(",");
data = line.substr(0,comma);
cout << "Line " << count << " "<< "is "<< data << endl;
count++;
}
infile.close();
string sent = "i,am,the,champion";
return 0;
}
You can use string::find 3 times to search for the third occurrence of the comma, and you must store the positions of the last 2 occurrences found in line, then use them as input data with string::substr and get the searched text:
std::string line ("17,17,\"Jackson & Kolmar\",\"Jackson & Kolmar, Eastbound, Southeast Corner\",41.87685748,-87.73934698,0,,1");
std::size_t found=0, foundBack;
int i;
for(i=0;i<3 && found!=std::string::npos;i++){
foundBack = found;
found=line.find(",",found+1);
}
std::cout << line.substr(foundBack+1,found-foundBack-1) << std::endl;
You can read the whole line of the file intoa string and then use stringstream to give you each piece one at a time up until and exluding the commas. Then you can fill up your arrays. I am assuming that you wanted each line in it's own array and that you wanted unlimited arrays. The best way to do that is to have an array of arrays.
std::string Line;
std::array<std::array<string>> Data;
while (std::getline(infile, Line))
{
std::stringstream ss;
ss << Line;
Data.push_back(std::vector<std::string>);
std::string Temp;
while (std::getline(ss, Temp, ','))
{
Data[Data.size() - 1].push_back(Temp);
}
}
This way you will have a vector, full of vectors, each of which conatining strings of all your data in that line. To access the strings as numbers, you can use std::stoi(std::string) which converts a string to an integer.

C++ ignore alphabetical characters when reading input from a file

I have a program that takes an input stream from a text file, which contains positive integers, delimited by spaces. The file contains only numbers and one instance of abc which my program should ignore before continuing to read data from the file.
this is my code and it does not work
int line;
in >> line;
in.ignore(1, 'abc');
in.clear();
could someone specify what the problem is? essentially, I want to discard the alpha input, clear cin and continue to read from file but I get an infinite loop.
This code should work
I get three parts from the input stream, and put the useful parts into a stringstream and read from it
int part1, part2;
std::string abc;
in >> part1 >> abc >> part2;
std::stringstream ss;
ss << part1 << part2;
int line;
ss >> line
You can explicitely ignore any alphabetical character this way:
#include <locale>
#include <iostream>
std::istream& read_number(std::istream& is, int& number) {
auto& ctype = std::use_facet<std::ctype<char>>(is.getloc());
while(ctype.is(std::ctype_base::alpha, is.peek())) is.ignore(1);
return is >> number;
}
int main() {
using std::string;
using std::cin;
using std::locale;
int number;
while(read_number(std::cin, number)) {
std::cout << number << ' ';
}
}
For input like "452abc def 23 11 -233b" this will produce "452 23 11 -233".

Elegant solution to take input to a vector<int>

I am trying to create an vector <int> whose size is not pre-defined. It should take in numbers as long as there are numbers in the input terminal and should stop reading when I hit Enter. I tried many solutions including the ones given here and here. In the second case, I can enter a non-integer to terminate the input to the vector. If I use the first solution (code added below), it listens to the input indefinitely.
Code:
#include <iostream>
#include <vector>
#include <string>
#include <sstream>
#include <iterator>
using std::cout;
using std::cin;
using std::vector;
using std::string;
using std::istringstream;
int main()
{
//cout << "Enter the elements of the array: \n";
//vector <int> arr ( std::istream_iterator<int>( std::cin ), std::istream_iterator<int>() );
vector <int> arr;
string buf;
cout << "Enter the elements of the array: \n";
while(getline(cin, buf))
{
istringstream ssin(buf);
int input;
while(ssin >> input)
{
arr.push_back(input);
}
}
cout << "The array: \n";
for(size_t i = 0; i < arr.size(); i++)
{
cout << arr[i] << " ";
}
return 0;
}
1) I don't feel that typing in a character or a very large number to end listening to input is very elegant. However, the solution with istringstream seems to be the way to go. I am not sure why it doesn't work.
2) Is there any way to detect the Enter from keyboard to terminate listening to input? I tried using cin.get(), but it changed the numbers in the vector.
3) Any other methods or suggestions?
Let's take things one step at a time.
We want to read up until enter is pressed. That means you probably want to use std:getline to read a line.
Then you want to parse it, so you want to put the line into an istringstream.
Then you want to read numbers. While you're reading them, you apparently want to ignore anything other than digits, and you want to keep reading even if you get to a group of digits that can't be converted to a number.
That leaves a few things that aren't entirely clear, such as what to do with that input that's too large to convert? Do you want to just skip to the next? Do you want to read some digits as a number, then read remaining digits as another number?
Likewise, what do you want to do if you get something like "123a456"? Should it be skipped completely, read as "123" (and the "a456" ignored)? Should it be read as "123" and "456", and just the "a" ignored?
For the moment let's assume that we're going to read space-separated groups of characters, and convert all those to numbers that we can. If something is too big to convert to a number, we'll ignore it (in its entirety). If we have a group like "123a456", we'll read the "123" as a number, and ignore the "a456".
To achieve this, we can do something like this:
std::string line;
std::getline(infile, line);
std::istringstream input(line);
std::string word;
std::vector<int> output;
while (input >> word) {
try {
int i = std::stoi(word);
output.push_back(i);
}
catch (...) {}
}
For example, given input like: "123a456 321 1111233423432434342343223344 9", this will read in [123, 321, 9].
Of course, I'm just taking a guess about your requirements, and I haven't worked at making this particularly clean or elegant--just a straightforward implementation of one possible set of requirements.
Please see the comments from #LearningC and #M.M.
#include <iostream>
#include <vector>
#include <string>
#include <sstream>
#include <iterator>
using std::cout;
using std::cin;
using std::vector;
using std::string;
using std::istringstream;
int main()
{
vector <int> arr;
string buf;
int input;
cout << "Enter the elements of the array: \n";
getline(cin, buf);
istringstream ssin(buf);
while(ssin >> input)
{
arr.push_back(input);
}
cout << "The array: \n";
for(size_t i = 0; i < arr.size(); i++)
{
cout << arr[i] << " ";
}
return 0;
}

how to read data delimited by space and save it to arrays,and then write it other order in new text file in c++

psedo code:
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
using namespace std;
int main() {
string line;
double beta[250];
char Batob[250], eq[250];
ifstream myfile("iter1/HMMemit0.txt");
if (myfile.is_open())
{
int i = 0;
while (getline(myfile, line))
{
istringstream iss(line);
if (!(iss >> Batob[i] >> eq[i] >> beta[i])){ //it store only B in Batob[i], but i want to save B00 in Batob[i], = in eq[i], and 0.524671 in beta[250]
break;
}
i++;
}
myfile.close();
}
else cout << "Unable to open file";
return 0;
}
my data stored in HMMemint0 like this
B00 = 0.524671
B01 = 0.001000
B02 = 0.001000
B10 = 0.001097
B11 = 0.001000
B12 = 0.001000
i want to read a line and save each term in each variable like B00 saved in name[i], and 0.001000 in beta[i].
and then, write it in this 0.524671(B00's value) 0.001097(B10's value) order like this
0.524671 0.001097
0.001000 0.001000
0.001000 0.001000
How can i do it? please help me.
You are having a char array for "BXX"s, whereas you want strings. Basically, you want a string array, or even vector. The problem is that only 'B' will be read from "BXX" into your first parameter.
This code works for me:
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
using namespace std;
int main() {
string line;
double beta[250];
string Batob[250];
char eq[250];
ifstream myfile("iter1/HMMemit0.txt");
if (myfile.is_open())
{
int i = 0;
while (getline(myfile, line))
{
istringstream iss(line);
iss >> Batob[i] >> eq[i] >> beta[i];
i++;
}
myfile.close();
}
else cout << "Unable to open file";
return 0;
}
Disclaimer: I was just fixing your code with the least impact, but of course if you start using proper C++ containers like vector, the i variable could be easily eliminated as the elements and the index would be maintained automatically.
Also, since you are using the equal sign ('=') all the time for the char array, it is a bit needless waste of memory, which could be severe in case of a big file.
I would say, using an associate container in the future would be even more productive for your BXX keys and their corresponding values on the right side.
Batob is an array of characters, so Batob[i] is a single character. That's why your program reads only one character. If you want to read 250 strings of characters you need to make room for them. The simplest (not necessarily the best, however) method is to declare an array like char Batob[250][100] – this would be an array of 250 arrays, 100 characters each. Then Batob[i] is a 100-chars array and you can input a string with iss >> Batob[i].