Reading time in hh:mm format from a line - c++

I have a file that consists of lines that look like this:
nameOfFood hh:mm PriceOfFood.
I have to count the income provided between 11:30 and 13:30 by each type of food.
So the output should look like this:
nameOfFood1 yielded $$$ between 11:30 and 13:30.
nameOfFood2 yielded $$$ between 11:30 and 13:30.
and so on.
Currently im using an ifstream f to do this (name and time are strings, price is integer):
f >> name >> time >>price;
My question is: how can I read the HH and MM parts of the timestamp into separate (integer) variables, so I can convert them into minutes (60*HH+MM) to make them comparable?

The way the input operators work is it stops at the point in the stream that no longer matches the target (in addition to on separators, like space). So, just treat the hour and minute as integers in the input stream, but you also have to swallow the colon character.
std::istringstream f("name 19:30 234");
std::string name;
int hour;
int minute;
int price;
char c;
f >> name >> hour >> c >> minute >> price;

Since your input format is fixed, you could do this:
std::string time = ...;
std::string hours(time, 0, 2); // start at 0, take 2 chars
std::string minutes(time, 3, 2); // start beyond ':', take 2 chars
This makes use of std::string's constructor taking another string, position, and character count.
I'll leave the actual integer conversion as an exercise.

simply you can use the c input method:
scanf("%d:%d",&H,&M);
don't forget to include stdio.h

Related

Splitting C++ strings using a Delimiter

Okay, So I've looked around on StackOverflow and I've stumbled across a way of splitting C++ via delimiters.
So far, I've looked at these, and I still don't understand it.
Parse (split) a string in C++ using string delimiter (standard C++)
https://www.oreilly.com/library/view/c-cookbook/0596007612/ch04s07.html
C++ spliting string by delimiters and keeping the delimiters in result
split a C++ string into two integers, which are delimited by ":"
From my understanding, I need to use a delimiter, using a variable that houses the delimiter, and then use the substr() method/function, but I don't understand the whole thing.
For instance, I saw this one example where it was referencing pos and npos, I don't understand that. And my other issue is, I wouldn't know how to do it with a string with multiple copies of the same delimiter.
My goal is to take a date like this: "29/01/2022 • 05:25:01" to split it into a struct for date and time, eg:
struct Date
{
int day; //Integer for days
int month; //Integer for months
int year; //Integer for years
};
struct Time
{
int hour; //Integer for hour of drop
int minute; //Integer for minute of drop
int second; //Integer for second of drop
int milisecond; //Integer for milisecond of drop
};
I've also looked at https://www.cplusplus.com/reference/, however I want to split it up so that they are stored in their own variables, eg:
string example
{
struct Date D;
struct Time T;
D.Day = 29;
D.Month = 01;
D.Year = 2022;
T.Hour = 5;
T.Minute = 25;
T.Second = 01;
}
Would someone be able to explain this to me in a simpler way, or show me a source that explains it easier? The main problem I have is not understanding certain words.
Any help is appreciated, I really am trying to learn, but I don't quite understand these subjects yet.
Let's go step by step, starting with the date:
29/01/2022 -- Day, Month, Year.
Given the following:
unsigned int day = 0u;
std::cin >> day;
The input of an integer skips whitespace until the first number character (for the first number character, also includes '+' and '-'). The extraction operator keeps reading characters, building a number, until a non-numeric character is reached:
2 --> day.
9 --> day.
The next character is '/', which is not a numeric character so the extraction operator returns the number 29.
The character '/' in this context is known as a delimiter, because it separates the day field from the month field.
Since it's a character, it has to be read using a character variable:
char delimiter = '\0';
std::cin >> delimiter;
Now, the delimiter is no longer in the buffer.
You can check the content of the delimiter variable or move on.
Reading the month is similar:
unsigned int month = 0U;
std::cin >> month;
Edit 1: delimiter and substrings
You could extract the month as a string using a delimiter:
std::string month_as_text;
std::getline(std::cin, month_as_text, '/');
The getline function above reads characters from std::cin, placing into the string month_as_text, until it finds the delimiter character '/'. You can then convert month_as_text into an integer variable.

Reading integer then rest of the line as a single string from input

Suppose I'm trying to read from the following input.txt
6 Jonathan Kim Jr
2 Suzie McDonalds
4 Patty
... and I want to store the first integers from every line and the rest of the strings as a string variable. This is what I have tried:
int num;
string name1, name2, name3;
while ( ins >> num >> name1 >> name2 >> name3 )
{
// do things
}
Unfortunately this won't work since line 2 and line 3 only has 2 and 1 strings in a respective order so the loop will terminate at the very first loop.
Is there a way to store the rest of the strings after an integer in a single variable, including the white spaces? For example, string variable name would hold:
"Jonathan Kim Jr" // first loop
"Suzie M" // second loop
"Patty" // third loop
I thought about using getline to achieve this as well, but that would require me to isolate the integers from the string and I was hoping there's a better approach do this. Perhaps using a vector?
By default, the >> operator splits on a space, so you could use that to pull the integer into the variable. You could then use getline to grab the rest of the line, and store that into the variable.
Example (if you are reading from std::cin):
int num;
std::string name;
std::cin >> num;
std::getline(std::cin, name);
Why don't use regular expressions (https://en.wikipedia.org/wiki/Regular_expression) to parse (https://en.cppreference.com/w/cpp/regex) the input? I think an expression something along the line of 2 subexpressions:
'^([0-1]+)\s([A-Za-z0-9_-/s]+)'

how to ignore n integers from input

I am trying to read the last integer from an input such as-
100 121 13 ... 7 11 81
I'm only interested in the last integer and hence want to ignore all
previous integers.
I thought of using cin.ignore but that won't work here due to
unknown integers (100 is of 3 digits, while 13 is of 2 digits & so on)
I can input integer by integer using a loop and do nothing with them. Is there a better way?
It all depends on the use case that you have.
Reading a none specified number of integers from std::cin is not as easy at it may seem. Because, in contrast to reading from a file, you will not have an EOF condition. If you would read from a file stream, then it would be very simple.
int value{};
while (fileStream >> value)
;
If you are using std::cin you could try pressing CTRL-D or CTRL-Z or whatever works on your terminal to produce an EOF (End Of File) condition. But usually the approach is to use std::getline to read a complete line until the user presses enter, then put this line into a std::istringstream and extract from there.
Insofar, one answer given below is not that good.
So, next solution:
std::string line{};
std::getline(std::cin, line);
std::istringstream iss{line};
int value{};
while (iss >> value)
;
You were asking
Is there a better way?
That also depends a little. If you are just reading some integers, then please go with above approach. If you would have many many values, then you would maybe waste time by unnecessarily converting many substrings to integers and loose time.
Then, it would be better, to first read the complete string, then use rfind to find the last space in the string and use std::stoi to convert the last substring to an integer.
Caveat: In this case you must be sure (or check with more lines of code) that there are no white space at the end and the last substring is really a number. That is a lot of string/character fiddling, which can most probably avoided.
So, I would recommend the getline-stringstream approach.
You can try this simple solution for dynamically ignoring rest of the values except the last given in this problem as shown:
int count = 0;
int values, lastValue; // lastValue used for future use
std::cout << "Enter your input: ";
while (std::cin >> values) {
lastValue = values; // must be used, otherwise values = 0 when loop ends
count++;
}
std::cout << lastValue; // prints
Note: A character must be required to stop the while(), hence it's better put a . at last.
Output example
Enter your input: 3 2 4 5 6 7.
7
Try this:
for( int i=0; i<nums_to_ignore; i++) {
int ignored;
std::cin >> ignored;
}

Reading multiple items in data file C++

I'm a C++ beginner. I'm trying to read a file that is formatted like so:
5 Christine Kim # 30.00 3 1
15 Ray Allrich # 10.25 0 0
...
number string # number number number
where each number has its own significance and the name does as well. I can get the file open and read the first two items but after the name I can't get the numbers after. This is my function right now:
void getItems( ifstream& dataFile, // in file
Employee item[], // class array so I can store the data later
int &transNum) // number of transactions
{
int id; // employee ID
char name[20]; // employee name
double hourlyPay; // pay per hour
int numDeps; // number of dependents
int type; // employee type
transNum = 0;
dataFile >> id;
dataFile.ignore(); // discard space before name
dataFile.getline( name, '#');
dataFile >> hourlyPay >> numDeps >> type;
}
I need it to read the first number, read the name, then read the last 3 numbers. After every name (maximum 20 characters) there is a # symbol where we should stop reading the name. I've tried adjusting the size of my char array for my string and other small fixes but nothing works. I realize that I will only get 1 line right now... I was just trying to get the first line to work before I made a loop to grab the other lines.
istream:getline needs a length parameter when used with a char array. Currently it is using '#' as the length value and using the default delimiter.
Change your code to
dataFile.getline( name, sizeof name, '#');
alternatively, use a std:string as the parameter to getline, then you don't need to specify a maximum size.
You're very close. The problem is likely to be the line
dataFile.ignore();
By default, ignore ignores everything up to EOF. What you want to do instead is ignore up to some number of characters until the next space. So that call would instead be:
datafile.ignore(100, ' ');
Where 100 is a purely arbitrary choice of number. Substitute your own rational value.
Next is your use of getline which must be told how many characters to read. Since your buffer is 20 characters, you need to inform getline like so:
getline(name, 20, '#');

Reading Data from a Text File and Ignoring Others

For a small portion of my project, I'm supposed to extract data from a text file using cin which my program will know where to cin from based on command line arguments. My issue is how to extract the four pieces of data and ignore the commas. For example, the .txt file will look like the following
(1,2,3,.)
(2,1,3,#)
(3,1,0,.)
In which case I need to extract the 1, the 2, the 3, and the . for the first line. Then move to the second line. When a blank newline is reached than I can exit the getline() scenario through a while loop.
I know I need to use getline() and I was able to extract the data by using the .at() function of the string generated by getline(). I became confused however when a coordinate such as the 1, the 2, or the 3, could be double digits. When this happened, my previous algorithm didn't work so I feel I'm overthinking things and there should be a simpler way to parse this data.
Thanks!
You can just use the >> operator to a dummy 'char' variable to read in the separators. This assumes you don't care about the 4th token and that it's always a single character:
char ch;
while (ss >> ch)
{
int a,b,c;
ss >> a >> ch >> b >> ch >> c >> ch >> ch >> ch;
}
A simple approach is to use sscanf, pass the string you read from cin to it as the first argument
sscanf(s, "(%d,%d,%d,%c)", &a, &b, &c))
If you want to parse the string from scratch, just focus the pattern.
In this case, the pattern is
'(', number, ',', number, ',', number, ',', char, ')'
So you can locate the three commas, then simply extract three numbers from between them.
A more complicated method is regex.
But C++ doesn't have native support for that (the Boost library does)