C++ Read an input file - c++

i'm having problems reading a file and saving the values.
So the input file contains:
3 5
W2 R3 W3 R4
And what i want is this:
F = 3
P = 5
char Ac[] = {'W','R','W','R'};
int acc[] = {2,3,3,4};
I already have the F = 3 and P = 5 but i don't know how to separate the other Strings.
I hope you can help me!

You can read character by character, skipping whitespaces.
Or you could read in a string, then split the string:
std::string rw_text;
std::vector<char> Ac;
std::vector<int> acc;
//...
while (input_file >> rw_text)
{
const char letter = rw_text[0];
const int number = rw_text[1] - '0';
Ac.push_back(letter);
acc.push_back(number);
}
You could also use a struct to keep your letters and numbers together, like a pair.
struct Letter_Number
{
char letter;
int number;
friend std::istream& operator>>(std::istream& input, Letter_Number& ln);
};
std::istream& operator>>(std::istream& input, Letter_Number& ln)
{
input >> ln.letter;
input >> ln.number;
return input;
}
//...
std::vector<Letter_Number> database;
Letter_Number ln;
//...
while (input_file >> ln)
{
database.push_back(ln);
}
A structure will keep the letters associated with their numbers. In a parallel array, you could have different offsets or the pair won't line up.
Also, with having a structure, the letter and number will be on the processor's same data cache line, so your program will be more efficient. Otherwise the processor will have to load in the Ac array, get the value, then load in the acc array and load in the character; wasting time reloading the data cache.

Related

How to convert ASCII Number to Integer which are taken from a file

Four digit numbers stored in a file are written in ASCII and separated by "Space". How do I read them as Integers?
Example file:
53545153 49575150 56485654 53565257 52555756 51534850 56575356 56505055 55525453
Here is what I tried:
ifstream infile("afile2.txt");
if (infile.is_open())
{
string str2;
char c;
while (!infile.eof())
{
getline(infile, str2, ' ');
for (std::string::iterator it = str2.begin(); it != str2.end(); ++it)
cout << (char)*it;
cout << " ";
}
}
infile.close();
In the above code (char)*it is picking only first digit but ASCII number start at 2 digit number i.e. 48.
Four digit numbers stored in a file are written in ASCII and separated by "Space", How do I read them as Integers. Example file: 53545153 49575150 56485654 53565257 52555756 51534850 56575356 56505055 55525453
Those look like 8 digit numbers.
To read a space separated number from a file simple use operator>> from a stream to an integer.
int value;
if (stream >> value) {
// Successfully read a number.
}
If you want to read all the values from a file. You can use a loop:
int value;
while (stream >> value) {
// Enter the body of the loop each time a number is read.
}
Note: Your usage of eof() is bad practice:
while (!infile.eof()) {
// If you enter here the file may be open and readable
// BUT there may be no data left in the file and thus the next
// attempt to read will fail if there is no data.
//
// This happens because the last successful read will read up-to
// but not past the EOF. So you have read all the data but not read
// past the EOF so eof() will return false.
}
More Info
So how do we read 2 digit numbers from groups of 8 digit larger numbers that are space separated.
Well we want to make it work like standard stream readding so we still want to use the operator>> to read from the stream. But none of the built in types read two digit numbers. So we need to define our own class that will read a two digit number.
struct TwoDigit
{
int value; // store the result here
operator int() {return value;} // Convert TwoDigit to integer
};
std::ostream& operator<<(std::ostream& str, TwoDigit const& data) {
str << data.value; // You can do something more complicated
// for printing but its not the current question
// so I am just going to dump the value out.
}
std::istream& operator>>(std::istream& str, TwoDigit& data) {
char c1 = 'X';
char c2 = 'Y';
if (str >> c1 >> c2) {
// successfully read two characters from the stream.
// Note >> automatically drops white space (space return etc)
// so we don't need to worry about that.
if (('0' <= c1 && c1 <= '9') && ('0' <= c2 && c2 <= '9')) {
// We have all good data.
// So let us update the vale.
data.value = ((c1 - '0') * 10) + (c2 - '0');
}
else {
// We have bad data read from the stream.
// So lets mark the stream as bad;
str.clear(std::ios::failbit);
}
}
return str;
}
Now in your code you can simply read
TwoDigit data;
if (stream >> data) {
// Read a single two digit value correctly.
}
// or for a loop:
while(stream >> data) {
// Keep reading data from the stream.
// Each read will consume two digits.
}
// or if you want to fill a vector from a stream.
std::vector<TwoDigit> data(std::istream_iterator<TwoDigit>(stream),
std::istream_iterator<TwoDigit>());
// You can even create a vector of int just as easily.
// Because the TwoDigit has an `operator int()` to convert to int.
std::vector<int> data(std::istream_iterator<TwoDigit>(stream),
std::istream_iterator<TwoDigit>());
This could be an approach if I've understood the problem correctly.
#include <cmath>
#include <iostream>
#include <string>
#include <vector>
std::vector<int> conv(std::istream& is) {
std::vector<int> retval;
std::string group;
while(is >> group) { // read "53545153" for example
int mul =
static_cast<int>(std::pow(10, (group.size() / 2) - 1)); // start at 1000
int res = 0;
for(size_t i = 0; i < group.size(); i += 2, mul /= 10) {
// convert "53" to dec ASCII char 53 ('5') and then to an int 5 and
// multiply by 1000 (mul)
res += (((group[i] - '0') * 10 + (group[i + 1] - '0')) - '0') * mul;
}
retval.emplace_back(res); // store
}
return retval;
}
Testing the function:
#include <sstream>
int main() {
std::istringstream is(
"53545153 49575150 56485654 53565257 52555756 51534850 56575356 56505055 55525453");
auto r = conv(is);
for(int x : r) {
std::cout << x << "\n";
}
}
Output:
5635
1932
8086
5849
4798
3502
8958
8227
7465

Find number of items in .txt file

I'm looking for a way to find the number of items in a .txt file.
The file structure is as follows:
students.txt pricem 1441912123
house.pdf jatkins 1442000124
users.txt kevin_tomlinson 1442001032
accounts.mdb kevin_tomlinson 1442210121
vacation.jpg smitty83 1442300125
calendar.cpp burtons 1442588012
The result should be 18 in this example since there are 18 separate "words" in this file.
I need that value so I can iterate through the items and assign them to an array of structures (maybe there's a way to accomplish both of these steps together?):
// my structure
struct AccessRecord
{
string filename;
string username;
long timestamp;
};
// new instance of AccessRecord
// max possible records: 500
AccessRecord logRecords[500];
// while file has content
while (!fin.eof())
{
// loop through file until end
// max possible records: 500
for (int i = 0; i < 500; i++) // need to figure out how to iterate
{
fin >> logRecords[i].filename
>> logRecords[i].username
>> logRecords[i].timestamp;
}
}
Which will then be written to the screen.
So the question is, how do I find the count? Or is there a better way?
You know that each line contains a string, a string and a long, so you can iterate with:
std::vector<AccessRecord> logs;
std::string fname, uname;
long tstamp;
while(fin >> fname >> uname >> tstamp) {
logs.push_back(AccessRecord(fname, uname, tstamp));
//To avoid copies, use: (thanks #Rakete1111!)
//logs.emplace_back(std::move(fname), std::move(uname), tstamp);
}
This is assuming you've created a constructor for your struct like:
AccessRecord(std::string f, std::string u, long t)
: filename(f), username(u), timestamp(t) { }
Notice that I'm using an std::vector here instead of an array so that we don't even have to worry about the number of items, since the vector will resize itself dynamically!
You should overload operator>> for your structure:
struct AccessRecord
{
string filename;
string username;
long timestamp;
friend std::istream& operator>>(std::istream& input, AccessRecord& ar);
};
std::istream& operator>>(std::istream& input, AccessRecord& ar)
{
input >> ar.filename;
input >> ar.username;
input >> ar.timestamp;
return input;
}
This allows you to simplify your input function:
AccessRecord ar;
std::vector<AccessRecord> logs;
//...
while (fin >> ar)
{
database.push_back(ar);
}
Usually, if you are accessing an objects data members directly outside of the class or structure, something is wrong. Search the internet for "data hiding", "c++ encapsulation" and "c++ loose coupling".

How to read pieces of string into a class array C++

I have an array of dvd from a Video class I created
Video dvd[10];
each video has the property,
class Video {
string _title;
string _genre;
int _available;
int _holds;
public:
Video(string title, string genre, int available, int holds);
Video();
void print();
void read(istream & is, Video dvd);
int holds();
void restock(int num);
string getTitle();
~Video();
};
I'm trying to fill up this array with data from my text file where each info such as the title and genre is separated by a comma
Legend of the seeker, Fantasy/Adventure, 3, 2
Mindy Project, Comedy, 10, 3
Orange is the new black, Drama/Comedy, 10, 9
I've tried using getline(in, line, ',') but my brain halts when its time to insert each line into the dvd array.
I also created a read method to read each word separated by a whitespace but I figured thats not what I really want.
I also tried to read a line with getline, store the line in a string and split it from there but I get confused along the line.
**I can get the strings I need from each line, my confusion is in how to insert it into my class array in the while loop especially when I can only read one word at a time.
I need help on what approach I should follow to tackle this problem.
**My code
#include <iostream>
#include <fstream>
#include <cassert>
#include <vector>
#define MAX 10
using namespace std;
class Video {
string _title;
string _genre;
int _available;
int _holds;
public:
Video(string title, string genre, int available, int holds);
Video();
void print();
void read(istream & is, Video dvd);
int holds();
void restock(int num);
string getTitle();
~Video();
};
Video::Video(string title, string genre, int available, int holds){
_title = title;
_genre = genre;
_available = available;
_holds = holds;
}
void Video::read (istream & is, Video dvd)
{
is >> _title >> _genre >> _available>>_holds;
dvd = Video(_title,_genre,_available,_holds);
}
int Video::holds(){
return _holds;
}
void Video::restock(int num){
_available += 5;
}
string Video::getTitle(){
return _title;
}
Video::Video(){
}
void Video::print(){
cout<<"Video title: " <<_title<<"\n"<<
"Genre: "<<_genre<<"\n"<<
"Available: " <<_available<<"\n"<<
"Holds: " <<_holds<<endl;
}
Video::~Video(){
cout<<"DESTRUCTOR ACTIVATED"<<endl;
}
int main(int params, char **argv){
string line;
int index = 0;
vector<string> tokens;
//Video dvd = Video("23 Jump Street", "comedy", 10, 3);
//dvd.print();
Video dvd[MAX];
dvd[0].holds();
ifstream in("input.txt");
/*while (getline(in, line, ',')) {
tokens.push_back(line);
}
for (int i = 0; i < 40; ++i)
{
cout<<tokens[i]<<endl;
}*/
if(!in.fail()){
while (getline(in, line)) {
dvd[index].read(in, dvd[index]);
/*cout<<line<<endl;
token = line;
while (getline(line, token, ',')){
}
cout<<"LINE CUT#####"<<endl;
cout<<line<<endl;
cout<<"TOKEN CUT#####"<<endl;*/
//dvd[index] =
index++;
}
}else{
cout<<"Invalid file"<<endl;
}
for (int i = 0; i < MAX; ++i)
{
dvd[i].print();
}
}
First, I would change the Video::read function into an overload of operator >>. This will allow the Video class to be used as simply as any other type when an input stream is being used.
Also, the way you implemented read as a non-static member function returning a void is not intuitive and very clunky to use. How would you write the loop, and at the same time detect that you've reached the end of file (imagine if there are only 3 items to read -- how would you know to not try to read a fourth item)? The better, intuitive, and frankly, de-facto way to do this in C++ is to overload the >> operator.
(At the end, I show how to write a read function that uses the overloaded >>)
class Video
{
//...
public:
friend std::istream& operator >> (std::istream& is, Video& vid);
//..
};
I won't go over why this should be a friend function, as that can be easily researched here on how to overload >>.
So we need to implement this function. Here is an implementation that reads in a single line, and copies the information to the passed-in vid:
std::istream& operator >> (std::istream& is, Video& vid)
{
std::string line;
std::string theTitle, theGenre, theAvail, theHolds;
// First, we read the entire line
if (std::getline(is, line))
{
// Now we copy the line into a string stream and break
// down the individual items
std::istringstream iss(line);
// first item is the title, genre, available, and holds
std::getline(iss, theTitle, ',');
std::getline(iss, theGenre, ',');
std::getline(iss, theAvail, ',');
std::getline(iss, theHolds, ',');
// now we can create a Video and copy it to vid
vid = Video(theTitle, theGenre,
std::stoi(theAvail), // need to change to integer
std::stoi(theHolds)); // same here
}
return is; // return the input stream
}
Note how vid is a reference parameter, not passed by value. Your read function, if you were to keep it, would need to make the same change.
What we did above is that we read the entire line in first using the "outer" call to std::getline. Once we have the line as a string, we break down that string by using an std::istringstream and delimiting each item on the comma using an "inner" set of getline calls that works on the istringstream. Then we simply create a temporary Video from the information we retrieved from the istringstream and copy it to vid.
Here is a main function that now reads into a maximum of 10 items:
int main()
{
Video dvd[10];
int i = 0;
while (i < 10 && std::cin >> dvd[i])
{
dvd[i].print();
++i;
}
}
So if you look at the loop, all we did is 1) make sure we don't go over 10 items, and 2) just use cin >> dvd[i], which looks just like your everyday usage of >> when inputting an item. This is the magic of the overloaded >> for Video.
Here is a live example, using your data.
If you plan to keep the read function, then it would be easier if you changed the return type to bool that returns true if the item was read or false otherwise, and just calls the operator >>.
Here is an example:
bool Video::read(std::istream & is, Video& dvd)
{
if (is.good())
{
is >> dvd;
return true;
}
return false;
}
And here is the main function:
int main()
{
Video dvd[10];
int i = 0;
while (i < 10 && dvd[i].read(std::cin, dvd[i]))
{
dvd[i].print();
++i;
}
}
Live Example #2
However, I still say that the making of Video::read a non-static member makes the code in main clunky.

Reading an Input File And Store The Data Into an Array (beginner)!

The Input file:
1 4 red
2 0 blue
3 1 white
4 2 green
5 2 black
what I want to do is take every row and store it into 2D array.
for example:
array[0][0] = 1
array[0][1] = 4
array[0][2] = red
array[1][0] = 2
array[1][1] = 0
array[1][2] = blue
etc..
code Iam working on it:
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <vector>
using namespace std;
int convert_str_to_int(const string& str) {
int val;
stringstream ss;
ss << str;
ss >> val;
return val;
}
string getid(string str){
istringstream iss(str);
string pid;
iss >> pid;
return pid;
}
string getnumberofcolors(string str){
istringstream iss(str);
string pid,c;
iss >> pid>>c;
return c;
}
int main() {
string lineinfile ;
vector<string> lines;
ifstream infile("myinputfile.txt");
if ( infile ) {
while ( getline( infile , lineinfile ) ) {
lines.push_back(lineinfile);
}
}
//first line - number of items
int numofitems = convert_str_to_int(lines[0]);
//lopps items info
string ar[numofitems ][3];
int i = 1;
while(i<=numofitems ){
ar[i][0] = getid(lines[i]);
i++;
}
while(i<=numofitems ){
ar[i][1] = getarrivel(lines[i]);
i++;
}
infile.close( ) ;
return 0 ;
}
when I add the second while loop my program stopped working for some reason!
is there any other way to to this or a solution to my program to fix it.
It's better to show you how to do it much better:
#include <fstream>
#include <string>
#include <vector>
using namespace std;
int main() {
ifstream infile("myinputfile.txt"); // Streams skip spaces and line breaks
//first line - number of items
size_t numofitems;
infile >> numofitems;
//lopps items info
vector<pair<int, pair<int, string>> ar(numofitems); // Or use std::tuple
for(size_t i = 0; i < numofitems; ++i){
infile >> ar[i].first >> ar[i].second.first >> ar[i].second.second;
}
// infile.close( ) ; // Not needed -- closed automatically
return 0 ;
}
You are probably solving some kind of simple algorithmic task. Take a look at std::pair and std::tuple, which are useful not only as container for two elements, but because of their natural comparison operators.
The answer given is indeed a much better solution than your's. I figured i should point out some of your design flaws and give some tips too improve it.
You redefined a function that already exists in the standard, which is
std::stoi() to convert a string to an integer. Remember, if a function
exists already, it's OK to reuse it, don't think you have to reinvent what's
already been invented. If you're not sure search your favorite c++ reference guide.
The solution stores the data "as is" while you store it as a full string. This doesn't really make sense. You know what the data is beforehand, use that to your advantage. Plus, when you store a line of data like that it must be parsed, converted, and then constructed before it can be used in any way, whereas in the solution the data is constructed once and only once.
Because the format of the data is known beforehand an even better way to load the information is by defining a structure, along with input/output operators. This would look something like this:
struct MyData
{
int num1;
int num2;
std::string color;
friend std::ostream& operator << (std::ostream& os, const MyData& d);
friend std::istream& operator >> (std::istream& os, const MyData& d);
};
Then you could simply do something like this:
...
MyData tmp;
outfile << tmp;
vData.push_back(tmp);
...
Their is no question of intent, we are obviously reading a data type from a stream and storing it in a container. If anything, it's clearer as to what you are doing than either your original solution or the provided one.

Extract numbers from a line of string in c++

I am making a natural language calculator in C++. The user will input a line of string for calculation. The program will extract the numbers and the operation and apply it accordingly. Following is part of my code
#include<iostream>
#include<string>
#include<sstream>
using namespace std;
int main()
{
string inp;
float n1,n2;
string s1,s2;
cout<<"Enter your string"<<endl;
getline(cin,inp);
stringstream ss;
ss.str(inp);
ss>>s1>>n1>>s2>>n2;
}
The program will run successfully if the user enters in correct format i.e Add 2 and 3, Subtract 8 from 12.
But the problem is in two cases
If the user enters in some other format like "7 plus 6".
Even in the correct format but only one number "square root of 25".
Is there a solution which can extract the floats regardless of the position or number of floats?
Thanks
If what you want to do is literally extract the floats, you can take advantage of the fact that std::stof can additionally return where it leaves off, which you can use to determine if the entire "word" is a float (e.g. for "6c") and catch the invalid_argument for words that are definitely not floats (e.g. for "plus"):
std::vector<float> getFloats(const std::string& s) {
std::istringstream iss(s);
std::string word;
std::vector<float> result;
size_t pos = 0;
while (iss >> word) {
try {
float f = std::stof(word, &pos);
if (pos == word.size()) {
result.push_back(f);
}
}
catch (std::invalid_argument const& ) {
// no part of word is a float
continue;
}
}
return result;
}
With that, getFloats("7 plus 6") yields {7, 6} and getFloats("square root of 25") yields {25}.