I need to read in some lines from a text file (amount of lines will be known during run time) but an example could be something like this:
Forecast.txt:
Day 0:S
Day 3:W
Day 17:N
My idea was to create a class which I did:
class weather
{
int day;
char letter;
};
Then create a vector of class as so:
vector<wather>forecast;
and now here is where I'm stuck. So I think I'd use a while loop?
id use my ifstream to read the info in and use a string to hold the information im reading in.
What I want to do is read in each line and extract the day number so in this example the 0, 3 and 15 and get the letter so S, W, N and store it in the vector of the class.
I was wondering if there's any way to do that? I could be coming at this wrong so forgive me im new to c++ and trying to figure this out.
Thank you for helping!
Your can use std::istringstream to parse each line, eg:
#include <sstream>
while (getline(in_s1, lines2))
{
istringstream iss(lines2);
string ignore1; // "Day"
char ignore2; // ":"
forecast f;
if (iss >> ignore1 >> f.day >> ignore2 >> f.letter)
weather.push_back(f);
}
Live Demo
Alternatively, you can parse each line using std::regex and related classes.
istringstream and the >> operator is probably the neatest C++ way to do it, as described in Remy's answer. In case you prefer to be a little less reliant on the stream magic and a bit more explicit, you can find the tokens you need and then extract them directly from the string.
Something like this:
while (getline(in_s1, lines2))
{
size_t startPos = lines2.find(' '); //get position of the space before the day
size_t endPos = lines2.find(':', startPos); //get position of the colon after the day
string day = lines2.substr (startPos+1, endPos-startPos-1); //extract the day
forecast f;
f.day = stoi(day); //stoi only supported since C++11, otherwise use atoi
f.letter = lines2[endPos+1];
weather.push_back(f);
}
Related
An input file is entered with the following data:
Juan Dela Cruz 150.50 5
'Juan Dela Cruz' is a name that I would like to assign to string A,
'150.50' is a number I would like to assign to float B
and 5 is a number I would like to assign to int C.
If I try cin, it is delimited by the spaces in between.
If I use getline, it's getting the whole line as a string.
What would be the correct syntax for this?
If we analyze the string, then we can make the following observation. At the very end, we have an integer. In front of the integer we have a space. And in front of that the float value. And again in fron of that a space.
So, we can simply look from the back of the string for the 2nd last space. This can easily be achieved by
size_t position = lineFromeFile.rfind(' ', lineFromeFile.rfind(' ')-1);
We need a nested statement of rfind please see here, version no 3.
Then we build a substring with the name. From start of the string up to the found position.
For the numbers, we put the rest of the original string into an std::istringstream and then simply extract from there.
Please see the following simple code, which has just a few lines of code.
#include <iostream>
#include <string>
#include <cctype>
#include <sstream>
int main() {
// This is the string that we read via getline or whatever
std::string lineFromeFile("Juan Dela Cruz 150.50 5");
// Let's search for the 2nd last space
size_t position = lineFromeFile.rfind(' ', lineFromeFile.rfind(' ')-1);
// Get the name as a substring from the original string
std::string name = lineFromeFile.substr(0, position);
// Put the numbers in a istringstream for better extraction
std::istringstream iss(lineFromeFile.substr(position));
// Get the rest of the values
float fValue;
int iValue;
iss >> fValue >> iValue;
// Show result to use
std::cout << "\nName:\t" << name << "\nFloat:\t" << fValue << "\nInt:\t" << iValue << '\n';
return 0;
}
Probably simplest in this case would be to read whole line into string and then parse it with regex:
const std::regex reg("\\s*(\\S.*)\\s+(\\d+(\\.\\d+)?)\\s+(\\d+)\\s*");
std::smatch match;
if (std::regex_match( input, match, reg)) {
auto A = match[1];
auto B = std::stof( match[2] );
auto C = std::stoi( match[4] );
} else {
// error invalid format
}
Live example
As always when the input does not (or sometimes does not) match a strict enough syntax, read the whole line and then apply the rules which to a human are "obvious".
In this case (quoting comment by john):
Read the whole string as a single line. Then analyze the string to work out where the breaks are between A, B and C. Then convert each part to the type you require.
Specifically, you probably want to use reverse searching functions (e.g. https://en.cppreference.com/w/cpp/string/byte/strrchr ), because the last parts of the input seem the most strictly formatted, i.e. easiest to parse. The rest is then the unpredictable part at the start.
either try inputting the different data type in different lines and then use line breaks to input different data types or use the distinction to differentiate different data types like adding a . or comma
use the same symbol after each data package, for example, Juan Dela Cruz;150.50;5 then you can check for a ; and separate your string there.
If you want to use the same input format you could use digits as an indicator to separate them
In C++, I'd like to read from an input file which contains different kind of datas: first the name of a contestant (2 or more strings with whitespaces), then an ID (string without whitespaces, always beginning with a number), then another strings without ws and a numbers (the sports and their achieved places).
For example:
Josh Michael Allen 1063Szinyei running 3 swimming 1 jumping 1
I show you the code what I started to write and then stucked..
void ContestEnor::next()
{
string line;
getline(_f , line);
if( !(_end = _f.fail()) ){
istringstream is(line);
is >> _cur.contestant >> _cur.id; // here I don't know how to go on
_cur.counter = 0;
//...
}
}
Thank you for your help in advance.
You should look into using std::getline with a delimiter. This way, you can delimit on a space character and read until you find a string where the first character in a number. Here is a short code example (this seems rather homework-like, so I don't want to write too much of it for you ;):
std::string temp, id;
while (std::getline(_f, temp, ' ')) {
if (temp[0] >= 0 && temp[0] <= '9') {
id = temp;
}
// you would need to add more code for the rest of the data on that line
}
/* close the file, etc. */
This code should be pretty self-explanatory. The most important thing to know is that you can use std::getline to get data up until a delimiter. The delimiter is consumed, just like the default behavior of delimiting on a newline character. Thus, the name getline isn't entirely accurate - you can still get only part of a line if you need to.
int i = 5;
char c = 'n';
string st = "cool";
ofstream my("we.txt");
my <<st<<","<<c<<","<<i<<","<<endl;
string s;
ifstream your("we.txt");
while(your){
getline(your, st, ',');
your>>c;
your.ignore(1);
your>>i;
your.ignore(1);
cout<<st<<","<<c<<","<<i<<endl;
}
my.close();
I don't even know what your.ignore(1) stands for, but somehow it works. The problem is that it print the result twice, why?
Can someone explain me how to handle the info that I've written in the file? If I wanted to save in a file 3 info string trade, double price and char sold (y/n), about every item I have how can I manage it?
It would look like this
Timberland, 40, n;
Gucci, 10, y; ..... etc..
I need it now, cause tomorrow I have a test, I appreciate your help, and sorry for my english!
As for the problem with the double-printing, it's because the eofbit flag is not set until after you read from beyond the end of the file. That means your loop will iterate once to many.
I suggest you instead use getline to read the complete line (in the condition of the loop), and then use e.g. std::istringstream to parse the line.
So do e.g.
while (std::getline(your, fullLine))
{
std::istringstream istr(fullLine);
getline(istr, st, ',');
istr >> c;
// etc.
}
I am working on a program in c++ and I need to read an entire string of text from a file. The file contains an address on one of the lines like this "123 Easy Ave" this has to be pulled into one string or char. Here is the code I have:
The data file:
Matt Harrold
307C Meshel Hall
1000 .01 4
The data is made up of a first and last name which become CustomerName, the next line is the address which is to populate Address, Then three numbers: principle, InterestRate, Years.
The code:
float InterestRate = 0;
int Years = 0;
char Junk [20];
int FutureValue;
float OnePlusInterestRate;
int YearNumber;
int count = 0;
char CustomerName;
string Address;
int * YearsPointer;
CustomerFile >> CustomerName
>> Address
>> Principle
>> InterestRate
>> Years;
Right now it only pulls in "103C" and stops at the space... Help is greatly appreciated!
Edit: In response to feedback on my question, I have edited it to use the more appropriate std::getline instead of std::istream::getline. Both of these would suffice, but std::getline is better suited for std::strings and you don't have to worry about specifying the string size.
Use std::getline() from <string>.
There is a good reference and example here: http://www.cplusplus.com/reference/string/getline/.
You'll also need to be careful combining the extraction (>>) operator and getline. The top answer to this question (cin>> not work with getline()) explains briefly why they shouldn't be used together. In short, a call to cin >> (or whatever input stream you are using) leaves a newline in the stream, which is then picked up by getline, giving you an empty string. If you really want to use them together, you have to call std::istream::ignore in between the two calls.
use std::getline from the <string> header.
I need to make a program in C++ that must read and write text files line by line with an specific format, but the problem is that in my PC I work in Windows, and in College they have Linux and I am having problems because of line endings are different in these OS.
I am new to C++ and don't know could I make my program able read the files no matter if they were written in Linux or Windows. Can anybody give me some hints? thanks!
The input is like this:
James White 34 45.5 10 black
Miguel Chavez 29 48.7 9 red
David McGuire 31 45.8 10 blue
Each line being a record of a struct of 6 variables.
Using the std::getline overload without the last (i.e. delimiter) parameter should take care of the end-of-line conversions automatically:
std::ifstream in("TheFile.txt");
std::string line;
while (std::getline(in, line)) {
// Do something with 'line'.
}
Here's a simple way to strip string of an extra "\r":
std::ifstream in("TheFile.txt");
std::string line;
std::getline(input, line));
if (line[line.size() - 1] == '\r')
line.resize(line.size() - 1);
If you can already read the files, just check for all of the newline characters like "\n" and "\r". I'm pretty sure that linux uses "\r\n" as the newline character.
You can read this page: http://en.wikipedia.org/wiki/Newline
and here is a list of all the ascii codes including the newline characters:
http://www.asciitable.com/
Edit: Linux uses "\n", Windows uses "\r\n", Mac uses "\r". Thanks to Seth Carnegie
Since the result will be CR LF, I would add something like the following to consume the extras if they exist. So once your have read you record call this before trying to read the next.
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
If you know the number of values you are going to read for each record you could simply use the ">>" method. For example:
fstream f("input.txt" std::ios::in);
string tempStr;
double tempVal;
for (number of records) {
// read the first name
f >> tempStr;
// read the last name
f >> tempStr;
// read the number
f >> tempVal;
// and so on.
}
Shouldn't that suffice ?
Hi I will give you the answer in stages. Please go trough in order to understand the code.
Stage 1: Design our program:
Our program based on the requirements should...:
...include a definition of a data type that would hold the data. i.e. our
structure of 6 variables.
...provide user interaction i.e. the user should be able to
provide the program, the file name and its location.
...be able to
open the chosen file.
...be able to read the file data and
write/save them into our structure.
...be able to close the file
after the data is read.
...be able to print out of the saved data.
Usually you should split your code into functions representing the above.
Stage 2: Create an array of the chosen structure to hold the data
...
#define MAX 10
...
strPersonData sTextData[MAX];
...
Stage 3: Enable user to give in both the file location and its name:
.......
string sFileName;
cout << "Enter a file name: ";
getline(cin,sFileName);
ifstream inFile(sFileName.c_str(),ios::in);
.....
->Note 1 for stage 3. The accepted format provided then by the user should be:
c:\\SomeFolder\\someTextFile.txt
We use two \ backslashes instead of one \, because we wish it to be treated as literal backslash.
->Note 2 for stage 3. We use ifstream i.e. input file stream because we want to read data from file. This
is expecting the file name as c-type string instead of a c++ string. For this reason we use:
..sFileName.c_str()..
Stage 4: Read all data of the chosen file:
...
while (!inFile.eof()) { //we loop while there is still data in the file to read
...
}
...
So finally the code is as follows:
#include <iostream>
#include <fstream>
#include <cstring>
#define MAX 10
using namespace std;
int main()
{
string sFileName;
struct strPersonData {
char c1stName[25];
char c2ndName[30];
int iAge;
double dSomeData1; //i had no idea what the next 2 numbers represent in your code :D
int iSomeDate2;
char cColor[20]; //i dont remember the lenghts of the different colors.. :D
};
strPersonData sTextData[MAX];
cout << "Enter a file name: ";
getline(cin,sFileName);
ifstream inFile(sFileName.c_str(),ios::in);
int i=0;
while (!inFile.eof()) { //loop while there is still data in the file
inFile >>sTextData[i].c1stName>>sTextData[i].c2ndName>>sTextData[i].iAge
>>sTextData[i].dSomeData1>>sTextData[i].iSomeDate2>>sTextData[i].cColor;
++i;
}
inFile.close();
cout << "Reading the file finished. See it yourself: \n"<< endl;
for (int j=0;j<i;j++) {
cout<<sTextData[j].c1stName<<"\t"<<sTextData[j].c2ndName
<<"\t"<<sTextData[j].iAge<<"\t"<<sTextData[j].dSomeData1
<<"\t"<<sTextData[j].iSomeDate2<<"\t"<<sTextData[j].cColor<<endl;
}
return 0;
}
I am going to give you some exercises now :D :D
1) In the last loop:
for (int j=0;j<i;j++) {
cout<<sTextData[j].c1stName<<"\t"<<sTextData[j].c2ndName
<<"\t"<<sTextData[j].iAge<<"\t"<<sTextData[j].dSomeData1
<<"\t"<<sTextData[j].iSomeDate2<<"\t"<<sTextData[j].cColor<<endl;}
Why do I use variable i instead of lets say MAX???
2) Could u change the program based on stage 1 on sth like:
int main(){
function1()
function2()
...
functionX()
...return 0;
}
I hope i helped...