C++; Using strings getline() not working with file input - c++

I can get getline() to work with cin (getline(cin,line)), but when I open a stream, it won't read the line from the file. The file contains a list of elements from the periodic table.
for Example:
H
He
O
etc...
EDIT:
However, when I try to cout the newly read line, it doesn't put it into var symbol at the line:
cout << "symbol: " << symbol << endl;
It doesn't give me anything out, but it should return the first element (H).
#include <fstream>
#include <iostream>
#include <vector>
#include <string>
using namespace std;
void print(vector <string> x)
{
cout << "list of elements:" << endl;
for (int i = 0; i < x.size(); ++i)
{
cout << x[i] << endl;
}
}
int main(int argc, char** argv)
{
string symbol;
vector <string> elementlist;
ifstream readin;
readin.open("Elements.txt");
getline(readin,symbol);
cout << "symbol: " << symbol << endl;
while (!readin.good())
{
elementlist.push_back(symbol);
getline(readin,symbol);
}
print (elementlist);
return 0;
}

I'd do it something like this:
#include <string>
#include <iostream>
#include <fstream>
#include <vector>
#include <iterator>
class line {
std::string data;
public:
friend std::istream &operator>>(std::istream &is, line &l) {
std::getline(is, l.data);
return is;
}
operator std::string() const { return data; }
};
int main() {
std::ifstream readin("Elements.txt");
// Initialize vector from data in stream:
//
std::vector<std::string>
element_list((std::istream_iterator<line>(readin)),
std::istream_iterator<line>());
// write data from vector to cout:
//
std::copy(element_list.begin(), element_list.end(),
std::ostream_iterator<std::string>(std::cout, "\n"));
return 0;
}

As I stated in my comment, your loop condition is wrong.
while (!readin.good())
{
elementlist.push_back(symbol);
getline(readin,symbol);
}
As it turns out, you want to loop using the condition readin.good(). Since !readin.good() will evaluate to false, you never actually enter the loop.

Related

Store a column from csv excel file to a vector double variable C++

I have a csv file in Excel that has a column of double data. I am trying to read that column and store the values in a vector variable using a while loop. I tried to use getline and then convert them into a double using stod.
The column has more values, but this is how the csv file looks like:
A
B
51.32
53.62
#include <iostream>
#include <fstream>
#include <vector>
using namespace std;
int main()
{
ifstream myFile("CData.csv");
int i= 0;
string val;
std::vector<double> y;
while (getline(myFile, val, ',')) {
y.push_back(stod(val));
cout << "test: " << y.at(i);
i++;
}
return 0;
}
I'm not sure what I'm doing wrong. Somehow, there is no output on the console app. I tried it with string ang it worked but when I try to convert to a double, it doesn't. Is there another way to do this, or did I miss something in the code? Thanks, I'm new to coding.
You need to first parse the line and then look at the line for comma separated data. Also you need to chek if data is digits or not.
Here is an example:
#include <iostream>
#include <fstream>
#include <vector>
#include <stdio.h>
#include <stdlib.h>
#include <sstream>
using namespace std;
int main()
{
ifstream myFile("CData.csv", std::ios::in);
int i= 0;
string val;
std::string line;
std::vector<double> y;
while (getline(myFile, line))
{
std::stringstream sstr(line);
while (getline(sstr, val, ','))
{
bool flag = true;
for (auto c : val)
if (!isdigit(c))
flag = false;
if (flag){
y.push_back( std::stod(val));
std::cout << "number: " << y.at(i) << std::endl;
i++;
}
else std::cout << "not number: " << val << std::endl;
}
}
return 0;
}
Good luck!

Can't iterate through all the words in thr file.txt

I have a txt file which contains two txt file references ei. main.txt contains eg1.txt and eg2.txt and i have to access the content in them and find the occurences of every word and return a string with the word and the documents it was preasent in(0 being eg1.txt and 1 being eg2.txt). My program compiles but I can't get past the first word I encounter. It gives the right result (word: 0 1) since the word is preasent in both the files and in the first position but it doesn't return the other words. Could someone please help me find the error? Thank you
string func(string filename) {
map<string, set<int> > invInd;
string line, word;
int fileNum = 0;
ifstream list (filename, ifstream::in);
while (!list.eof()) {
string fileName;
getline(list, fileName);
ifstream input_file(fileName, ifstream::in); //function to iterate through file
if (input_file.is_open()) {
while (getline(input_file, line)) {
stringstream ss(line);
while (ss >> word) {
if (invInd.find(word) != invInd.end()) {
set<int>&s_ref = invInd[word];
s_ref.insert(fileNum);
}
else {
set<int> s;
s.insert(fileNum);
invInd.insert(make_pair<string, set<int> >(string(word) , s));
}
}
}
input_file.close();
}
fileNum++;
}
Basically your function works. It is a little bit complicated, but i works.
After removing some syntax errors, the main problem is, that you do return nothing from you function. There is also no output statement.
Let me show you you the corrected function which shows some output.
#include <string>
#include <map>
#include <iostream>
#include <fstream>
#include <set>
#include <sstream>
#include <utility>
using namespace std;
void func(string filename) {
map<string, set<int> > invInd;
string line, word;
int fileNum = 0;
ifstream list(filename, ifstream::in);
while (!list.eof()) {
string fileName;
getline(list, fileName);
ifstream input_file(fileName, ifstream::in); //function to iterate through file
if (input_file.is_open()) {
while (getline(input_file, line)) {
stringstream ss(line);
while (ss >> word) {
if (invInd.find(word) != invInd.end()) {
set<int>& s_ref = invInd[word];
s_ref.insert(fileNum);
}
else {
set<int> s;
s.insert(fileNum);
invInd.insert(make_pair(string(word), s));
}
}
}
input_file.close();
}
fileNum++;
}
// Show the output
for (const auto& [word, fileNumbers] : invInd) {
std::cout << word << " : ";
for (const int fileNumber : fileNumbers) std::cout << fileNumber << ' ';
std::cout << '\n';
}
return;
}
int main() {
func("files.txt");
}
This works, I tested it. But maybe you want to return the findings to your main function. Then you should write:
#include <string>
#include <map>
#include <iostream>
#include <fstream>
#include <set>
#include <sstream>
#include <utility>
using namespace std;
map<string, set<int> > func(string filename) {
map<string, set<int> > invInd;
string line, word;
int fileNum = 0;
ifstream list(filename, ifstream::in);
while (!list.eof()) {
string fileName;
getline(list, fileName);
ifstream input_file(fileName, ifstream::in); //function to iterate through file
if (input_file.is_open()) {
while (getline(input_file, line)) {
stringstream ss(line);
while (ss >> word) {
if (invInd.find(word) != invInd.end()) {
set<int>& s_ref = invInd[word];
s_ref.insert(fileNum);
}
else {
set<int> s;
s.insert(fileNum);
invInd.insert(make_pair(string(word), s));
}
}
}
input_file.close();
}
fileNum++;
}
return invInd;
}
int main() {
map<string, set<int>> data = func("files.txt");
// Show the output
for (const auto& [word, fileNumbers] : data) {
std::cout << word << " : ";
for (const int fileNumber : fileNumbers) std::cout << fileNumber << ' ';
std::cout << '\n';
}
}
Please enable C++17 in your compiler.
And please see below a brushed up solution. A little bit cleaner and compacter, with comments and better variable names.
#include <string>
#include <map>
#include <iostream>
#include <fstream>
#include <set>
#include <sstream>
#include <utility>
using WordFileIndicator = std::map<std::string, std::set<int>>;
WordFileIndicator getWordsWithFiles(const std::string& fileNameForFileLists) {
// Here will stor the resulting output
WordFileIndicator wordFileIndicator{};
// Open the file and check, if it could be opened
if (std::ifstream istreamForFileList{ fileNameForFileLists }; istreamForFileList) {
// File number Reference
int fileNumber{};
// Read all filenames from the list of filenames
for (std::string fileName{}; std::getline(istreamForFileList, fileName) and not fileName.empty();) {
// Open the files to read their content. Check, if the file could be opened
if (std::ifstream ifs{ fileName }; ifs) {
// Add word and associated file number to set
for (std::string word{}; ifs >> word; )
wordFileIndicator[word].insert(fileNumber);
}
else std::cerr << "\n*** Error: Could not open '" << fileName << "'\n\n";
// Continue with next file
++fileNumber;
}
}
else std::cerr << "\n*** Error: Could not open '" << fileNameForFileLists << "'\n\n";
return wordFileIndicator;
}
// Some test code
int main() {
// Get result. All words and in which file they exists
WordFileIndicator data = getWordsWithFiles("files.txt");
// Show the output
for (const auto& [word, fileNumbers] : data) {
std::cout << word << " : ";
for (const int fileNumber : fileNumbers) std::cout << fileNumber << ' ';
std::cout << '\n';
}
}
There would be a much faster solution by using std::unordered_map and std::unordered_set
Please make sure your code is composed from many small functions. This improves readability, it easier to reason what code does, in such form parts of code can be reused in alternative context.
Here is demo how it can looks like and why it is better to have small functions:
#include <algorithm>
#include <filesystem>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <string>
#include <unordered_map>
#include <vector>
struct FileData
{
std::filesystem::path path;
int index;
};
bool operator==(const FileData& a, const FileData& b)
{
return a.index == b.index && a.path == b.path;
}
bool operator!=(const FileData& a, const FileData& b)
{
return !(a == b);
}
using WordLocations = std::unordered_map<std::string, std::vector<FileData>>;
template<typename T>
void mergeWordsFrom(WordLocations& loc, const FileData& fileData, T b, T e)
{
for (; b != e; ++b)
{
auto& v = loc[*b];
if (v.empty() || v.back() != fileData)
v.push_back(fileData);
}
}
void mergeWordsFrom(WordLocations& loc, const FileData& fileData, std::istream& in)
{
return mergeWordsFrom(loc, fileData, std::istream_iterator<std::string>{in}, {});
}
void mergeWordsFrom(WordLocations& loc, const FileData& fileData)
{
std::ifstream f{fileData.path};
return mergeWordsFrom(loc, fileData, f);
}
template<typename T>
WordLocations wordLocationsFromFileList(T b, T e)
{
WordLocations loc;
FileData fileData{{}, 0};
for (; b != e; ++b)
{
++fileData.index;
fileData.path = *b;
mergeWordsFrom(loc, fileData);
}
return loc;
}
WordLocations wordLocationsFromFileList(std::istream& in)
{
return wordLocationsFromFileList(std::istream_iterator<std::filesystem::path>{in}, {});
}
WordLocations wordLocationsFromFileList(const std::filesystem::path& p)
{
std::ifstream f{p};
f.exceptions(std::ifstream::badbit);
return wordLocationsFromFileList(f);
}
void printLocations(std::ostream& out, const WordLocations& locations)
{
for (auto& [word, filesData] : locations)
{
out << std::setw(10) << word << ": ";
for (auto& file : filesData)
{
out << std::setw(3) << file.index << ':' << file.path << ", ";
}
out << '\n';
}
}
int main()
{
auto locations = wordLocationsFromFileList("files.txt");
printLocations(std::cout, locations);
}
https://wandbox.org/permlink/nBbqYV986EsqvN3t

Inputting values into an array from a file with C++

The file does open and I get the message "File opened successfully". However I can't input data from the array in file "random.csv" into my inputFile object.
The data in random.csv is:
Boston,94,-15,65
Chicago,92,-21,72
Atlanta,101,10,80
Austin,107,19,81
Phoenix,112,23,88
Washington,88,-10,68
Here is my code:
#include "main.h"
int main() {
string item; //To hold file input
int i = 0;
char array[6];
ifstream inputFile;
inputFile.open ("random.csv",ios::in);
//Check for error
if (inputFile.fail()) {
cout << "There was an error opening your file" << endl;
exit(1);
} else {
cout << "File opened successfully!" << endl;
}
while (i < 6) {
inputFile >> array[i];
i++;
}
for (int y = 0; y < 6; y++) {
cout << array[y] << endl;
}
inputFile.close();
return 0;
}
Hello and welcome to Stack Overflow (SO). You can use std::getline() to read each line from the file, and then use boost::split() to split each line into words. Once you have an array of strings for each line, you can use a container of your liking to store the data.
In the example below I've used an std::map that stores strings and a vector of ints. Using a map will also sort the entrances using the key values, which means that the final container would be in alphabetical order. The implementation is very basic.
#include <iostream>
#include <vector>
#include <map>
#include <string>
#include <fstream>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/split.hpp>
#include <ctype.h>
typedef std::map<std::string,std::vector<int>> ContainerType;
void extract(ContainerType &map_, const std::string &line_)
{
std::vector<std::string> data;
boost::split(data, line_, boost::is_any_of(","));
// This is not the best way - but it works for this demo.
map_[data[0]] = {std::stoi(data[1]),std::stoi(data[2]),std::stoi(data[3])};
}
int main()
{
ContainerType map;
std::ifstream inputFile;
inputFile.open("random.csv");
if(inputFile.is_open())
{
std::string line;
while( std::getline(inputFile,line))
{
if (line.empty())
continue;
else
extract(map,line);
}
inputFile.close();
}
for (auto &&i : map)
{
std::cout<< i.first << " : ";
for (auto &&j : i.second)
std::cout<< j << " ";
std::cout<<std::endl;
}
}
Hope this helps.

Reading a File's Line with no Spaces into separate Variables

First time asking a question on this site, so here goes. I've been racking my brain for quite some time, but still can't seem to find the answer to this.
Let's say I have a file that reads as follows:
123456789John Doe 0001111.11
925219042Mary Jane 0000302.54
891492829Gertrude Marisou 0123467.76
How would I separate say, 123456789 and John into their own respective strings for input into a vector containing four variables? (Std::string, Std::string, Std::string, Double)
Here is my current code if you all would like to take a peek at it and tell me where I am going wrong.
#pragma once
#if !defined(__Account7_h__)
#define __Accoun7_h__
#include <string>
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
#include <sstream>
//Personal file for trimming the extra whitespace
#include "Trim.h"
class Account7 {
private:
std::string account_code;
std::string first_name;
std::string last_name;
double balance;
public:
//Getters, Setters, Initialization List and whatnot.
//On a separate file
#if !defined(__Vmanager7_h__)
#define __Vmanager7_h__
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
#include <sstream>
#include "Account7.h"
#include "Trim.h"
using namespace generic;
class Vmanager7 {
public:
int a = 1;
std::ifstream infile;
std::ofstream outputFile;
std::vector<Account7> _Account;
Account7 temp;
std::string Empl;
std::string scapeg;
std::string acc_c;
std::string fname;
std::string lname;
double bal;
int Managed() {
int count;
infile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
try {
infile.open("account.dat", std::ifstream::in);
}
catch (std::ios_base::failure &fail) {
std::cout << "File is not opening" << std::endl;
return 0;
}
infile.exceptions(std::ios::goodbit);
while (getline(infile, Empl)) {
count = 1;
std::istringstream ss(Empl);
while (getline(ss, scapeg)) {
if (count == 1)
acc_c = scapeg;
else if (count == 2)
fname = scapeg;
else if (count == 3)
lname = scapeg;
else
bal = atof(scapeg.c_str());
count++;
}
temp.setac(acc_c);
temp.setfn(fname);
temp.setln(lname);
temp.setba(bal);
_Account.push_back(temp);
}
infile.close();
outputFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
try {
outputFile.open("Aoutput.dat");
}
catch (std::ios_base::failure &fail) {
std::cout << "File opening fail" << std::endl;
return 0;
}
outputFile.exceptions(std::ios::goodbit);
for (int i = 0; i < _Account.size(); i++) {
std::cout << _Account[i].getac() << " " << _Account[i].getfn() << " " << _Account[i].getln() << " " << _Account[i].getba();
bal = _Account[i].getba();
bal -= int(bal);
if (bal == 0)
std::cout << ".00";
std::cout << '\n';
}
outputFile.close();
}
};
};
The output I get is something along the lines of this:
123456789John Doe 0001111.11 -9.25596e+61
925219042Mary Jane 0000302.54 -9.25596e+61
191492829Gertrude Marisou 0123467.76 -9.25596e+61
I would like the output to look just like the input. Any help would be immensely appreciated.

How to write a series of float from text using fstream

Example ABC.txt
10.f 30.2f 20.f
I want to retrieve those information and store inside my array. However i am unsure how to do it.
I dont understand what is
Then (if good), it calls num_get::get (using the stream's selected locale) to perform both the extraction and the parsing operations, adjusting the stream's internal state flags accordingly. Finally, it destroys the sentry object before returning.
std::fstream filestr("ABC.txt", std::fstream::in);
if(!filestr.good()) //Logical error on i/o operation
{
//Unable to process
filestr.close();
return;
}
unsigned index= 0;
unsigned count= 0;
while(filestr.good())
{
float buffer= 0.f;
filestr >> std::skipws >> buffer;
score[index]= buffer;
++index;
}
filestr.close();
There are a number of ways to do this. One way is using stringstreams, in combination with vectors and strings:
#include <fstream>
#include <iostream>
#include <string>
#include <cstdlib>
#include <sstream>
#include <vector>
using namespace std;
int main() {
std::ifstream filestr("C:\\nums.txt", std::fstream::in);
std::vector<double> numbers;
if (!(filestr.good())) {
std::cout << "BAD FILE" << std::endl;
exit(0);
}
else {
std::string temp;
double d = 0.0;
while(std::getline(filestr, temp)) {
std::istringstream iss(temp);
while(std::getline(iss, temp, ' ')) {
std::istringstream ist(temp);
ist >> f;
numbers.push_back(f);
}
}
}
//see that the vector has information in it
for (int i = 0; i < numbers.size(); i++) {
std::cout << numbers[i] << std::endl;
}
filestr.close();
return 0;
}
One thing to note is that you could also use iterators here, but that's something you could implement for yourself.
Super simple with istream_iterator. There is only one tricky bit in the code below. The vector constructor call needs an extra set of parens around the first argument to avoid the Most Vexing Parse.
#include <fstream>
#include <iostream>
#include <iterator>
#include <vector>
#include <algorithm>
using namespace std;
int
main (int argc, char** argv)
{
for (int i = 1; i < argc; ++i) {
ifstream in (argv[i]);
if (!in) {
cerr << "Failed to open " << argv[i] << endl;
continue;
}
vector<double> nums ((istream_iterator<double> (in)), istream_iterator<double> ());
copy (nums.begin (), nums.end (), ostream_iterator<double> (cout, "\n"));
}
return 0;
}