How to delete unnecessary new line from string while reading file? - c++

I have created a simple file reader function which use std::map with std::tuple. The code is as follow:
#include <iostream>
#include <fstream>
#include <vector>
#include <tuple>
#include <map>
#include <algorithm>
typedef std::map<std::string, std::tuple<int, double>> Map;
Map Readfile(std::string filename)
{
std::ifstream File(filename);
if (!File.is_open())
{
std::cout << "File '" << filename << "' does not exist.";
exit(1);
}
Map data;
std::string name;
int a;
double b;
while (std::getline(File, name, '\t') >> a >> b)
{
data.insert({name, std::tuple<int, double>(a, b)});
}
return data;
}
int main()
{
std::string file = "file_read_v3.txt";
auto mt = Readfile(file);
std::for_each(mt.begin(), mt.end(), [](std::pair<std::string,std::tuple<int, double>> it) {
std::cout << it.first << "\t" << std::get<0>(it.second) << "\t" << std::get<1>(it.second) << std::endl;
});
return 0;
}
The contents of the text file I read:
Yvis 25 63.25
Wogger X Y 2 6.2
Bilbo 111 81.3
Mary 29 154.8
The data in the file is separated by tabs ('\t'). When I compile the source code, I discovered a rather strange thing on the command line: for some reason, there is a new line break after reading each line. I see this on the command line:
Bilbo 111 81.3
Mary 29 154.8
Wogger X Y 2 6.2
Yvis 25 63.25
What is the solution to this problem? And how to avoid not sorting the scanned data?

Related

Why does getline() cut off CSV Input?

I'm trying to read and parse my CSV files in C++ and ran into an error.
The CSV has 1-1000 rows and always 8 columns.
Generally what i would like to do is read the csv and output only lines that match a filter criteria. For example column 2 is timestamp and only in a specific time range.
My problem is that my program cuts off some lines.
At the point where the data is in the string record variable its not cutoff. As soon as I push it into the map of int/vector its cutoff. Am I doing something wrong here?
Could someone help me identify what the problem truly is or maybe even give me a better way to do this?
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <sstream>
#include <iostream>
#include <map>
#include "csv.h"
using std::cout; using std::cerr;
using std::endl; using std::string;
using std::ifstream; using std::ostringstream;
using std::istringstream;
string readFileIntoString(const string& path) {
auto ss = ostringstream{};
ifstream input_file(path);
if (!input_file.is_open()) {
cerr << "Could not open the file - '"
<< path << "'" << endl;
exit(EXIT_FAILURE);
}
ss << input_file.rdbuf();
return ss.str();
}
int main()
{
int filterID = 3;
int filterIDIndex = filterID;
string filter = "System";
/*Filter ID's:
0 Record ID
1 TimeStamp
2 UTC
3 UserID
4 ObjectID
5 Description
6 Comment
7 Checksum
*/
string filename("C:/Storage Card SD/Audit.csv");
string file_contents;
std::map<int, std::vector<string>> csv_contents;
char delimiter = ',';
file_contents = readFileIntoString(filename);
istringstream sstream(file_contents);
std::vector<string> items;
string record;
int counter = 0;
while (std::getline(sstream, record)) {
istringstream line(record);
while (std::getline(line, record, delimiter)) {
items.push_back(record);
cout << record << endl;
}
csv_contents[counter] = items;
//cout << csv_contents[counter][0] << endl;
items.clear();
counter += 1;
}
I can't see a reason why you data is being cropped, but I have refactored you code slightly and using this it might be easier for you to debug the problem, if it doesn't just disappear on its own.
int main()
{
string path("D:/Audit.csv");
ifstream input_file(path);
if (!input_file.is_open())
{
cerr << "Could not open the file - '" << path << "'" << endl;
exit(EXIT_FAILURE);
}
std::map<int, std::vector<string>> csv_contents;
std::vector<string> items;
string record;
char delimiter = ';';
int counter = 0;
while (std::getline(input_file, record))
{
istringstream line(record);
while (std::getline(line, record, delimiter))
{
items.push_back(record);
cout << record << endl;
}
csv_contents[counter] = items;
items.clear();
++counter;
}
return counter;
}
I have tried your code and (after fixing the delimiter) had no problems, but I only had three lines of data, so if it is a memory issue it would have been unlikely to show.

Sorting a textfile that contains player name and score in descending order

I am trying to open a text file and then rearrange it in descending order, to show who has the highest score. In the text file there's the player name and their score.
I've managed to print out the textfile in c++, but I cannot find a way to sort it since the variables are in the text file.
#include <string>
#include <cstdio>
#include <fstream>
#include <algorithm>
#include <iostream>
#include <iterator>
#include <functional>
using namespace std;
struct player {
string name;
int score;
int position;
};
int main()
{
string line;
ifstream inFile;
inFile.open("C:/Users/kkpet/Desktop/highscore.txt");
if (inFile.is_open()) {
while (getline(inFile, line)) {
player x;
ifstream inFile;
inFile.open("C:/Users/kkpet/Desktop/highscore.txt");
cout << line << '\n';
}
inFile.close();
}
else
cout << "Unable to open text";
}
Assuming your text file looks like this:
Name1 1
Name2 1
Name4 5
Name3 6
you could do something like this:
#include <string>
#include <cstdio>
#include <fstream>
#include <algorithm>
#include <iostream>
#include <iterator>
#include <functional>
#include <vector>
int main()
{
std::string line;
std::ifstream inFile;
inFile.open("/C:/Users/kkpet/Desktop/highscore.txt");
if (inFile.is_open()) {
std::vector<std::pair<int, std::string> > score_vector;
std::string name;
int score;
while (inFile >> name >> score) {
score_vector.push_back(std::make_pair(score, name));
std::cout << line << '\n';
}
inFile.close();
std::sort(score_vector.begin(), score_vector.end());
std::reverse(score_vector.begin(), score_vector.end());
for(auto it = score_vector.begin(); it != score_vector.end(); ++it){
std::cout << "Name: " << it->second << " Score: " << it->first << std::endl;
}
}
else
std::cout << "Unable to open text";
}
You first read the file line by line using inFile << name << score directly gives you the name and score of the player. You then create a pair out of them with score as first, which just makes it easier to sort, you could also sort by the second element of a pair using your own compare function, but for simplicity I put it this way around. Then you can easily sort the vector with the std::sort method. Afterwards it needs to be reverted.
Full code with custom compare function:
#include <string.h>
#include <cstdio>
#include <fstream>
#include <algorithm>
#include <iostream>
#include <iterator>
#include <functional>
#include <vector>
// This is a compare funciton for the sort algorithm of std::sort. See [1]
bool compareScorePair(std::pair<std::string, int>&a, std::pair<std::string, int>&b){
if(a.second > b.second){return true;}
if(a.second == b.second){return a.first.compare(b.first) > 0;}
return false;
}
int main()
{
std::ifstream inFile;
inFile.open("C:/Users/kkpet/Desktop/highscore.txt");
if (inFile.is_open()) {
std::vector<std::pair<std::string, int> > score_vector;
std::string name;
int score;
while (inFile >> name >> score) { // Can be used to directly assign istream data to variables. See [2]
score_vector.push_back(std::make_pair(name, score)); // Storing data as pair, to keep relationships between score and name.
}
inFile.close();
std::sort(score_vector.begin(), score_vector.end(), compareScorePair); // Sort the vector with the custom compare function, See top of code.
int place = 1;
//auto is used purely for convenience. auto represents std::vector<std::pair<std::string, int> >::iterator here.
for(auto it = score_vector.begin(); it != score_vector.end(); ++it){
std::cout << "Place: " << place << " Name: " << it->first << " Score: " << it->second << std::endl;
++place;
}
// The whole for loop could look like this:
/*
for(uint i = 0; i < score_vector.size(); ++i){
std::string name_out = score_vector[i].first;
int score_out = score_vector[i].second;
std::cout << "Place: " << i << " Name: " << name_out << " Score: " << score_out << std::endl;
}
*/
}
else
std::cout << "Unable to open text";
}
Output:
Place: 1 Name: Name3 Score: 6
Place: 2 Name: Name4 Score: 5
Place: 3 Name: Name2 Score: 1
Place: 4 Name: Name1 Score: 1
Links:
[1]: https://en.cppreference.com/w/cpp/named_req/Compare
[2]: http://www.cplusplus.com/reference/istream/istream/operator%3E%3E/
Information on pair:
https://en.cppreference.com/w/cpp/utility/pair
Information on iterators (see auto keyword):
https://www.geeksforgeeks.org/iterators-c-stl/
No need to use C++ for this problem! Just enter this in the shell prompt.
sort -rk 2 highscore.txt > sorted_scores.txt
Explanation:
'sort' sorts a file, typically by the first letter.
The -k 2 option means to sort by the second column.
The -r option means to reverse (so highest score is on top).

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.

Writing a C++ Program to Search an Index File From the Linux Command Line

I've written a program that reads in a data file and creates a sorted index file from the data in the original file. However, I"m then supposed to write a second program that allows teh user to search this index file from the Linux command line. For example, they are supposed to be able to type
search 12382 prog5.idx
into the command line and have the information for that record displayed. I have no idea how to accomplish this.
I have written the code to create the index file (works):
#include <iostream>
#include <fstream>
#include <map>
#include <sstream>
#include <string>
#include <iomanip>
using namespace std;
class Record {
string name;
int code;
double cost;
public:
Record() {
}
Record(string tname,int tcode,double tcost) : name(tname),code(tcode),cost(tcost) {
}
friend ostream& operator<< (ostream &os, const Record& r);
};
//print function
ostream& operator<< (ostream &os, const Record& r) {
os << setw(10) << r.name << " " << setw(5) << r.code << " $" << setw(10) << setprecision(2) << fixed << r.cost ;
return os;
}
int main() {
std::map<int, Record> myMap;
ifstream data;
size_t offset_count = 0;
data.open("prog5.dat");
ofstream outFile("prog5.idx", ios::out);
//if file can't be opened, exit
if(!data) {
cerr << "Open Failure" << endl;
exit(1);
}
std::string line;
while (std::getline(data, line)) {
stringstream ss(line);
int key;
string name;
int code;
double cost;
if(ss >> key >> name >> code >> cost) {
Record r(name,code,cost);
myMap.insert( pair<int,Record>(key,r));
}
else {
cout << "Error";
}
}
// print what's stored in map
for(std::map<int,Record>::iterator x = myMap.begin(); x!=myMap.end(); ++x) {
cout << setw(10) << x->first << ": " << x->second << endl;
}
}
And get the following output when running the above code:
8: blank 0 $ 0.00
12165: Item16 30 $ 7.69
12345: Item06 45 $ 14.20
12382: Item09 62 $ 41.37
12434: Item04 21 $ 17.30
16541: Item12 21 $ 9.99
21212: Itme31 19 $ 8.35
34186: Item25 18 $ 17.75
41742: Item14 55 $ 12.36
Here's what I have so far for the second program:
#include <prog3.idx>
#include <iostream>
#include <fstream>
using namespace std;
int main(int argc, char** argv) {
if(argc < 3) {
std::cerr << "Too few arguments \n";
std::exit(EXIT_FAILURE);
}
int key = atoi(argv[1]);
const char* filename = argv[2];
ifstream input;
input.open("prog5.idx");
}
But I'm not sure where to go from there. Can someone help me out?
Use map or multimap and find in the STL. Make a datatype out of the remaining data with the index as the key. The program will have to read in the entire file first and then find the searched index.