Is there any easy way to read a line from a file, split the first text part into a string, then split the last number part into a float?
I have an issue that I haven't been able to find a good way to solve, mostly because I am relatively new to C++, but not new to programming. I have a file with several lines in it, one of them being:
Plain Egg 1.45
I need to be able to read that line and split the first part, "Plain Egg", into a string, and then the last part, 1.45, into a float, and then do that for the rest of the lines. The following is some code I have so far, but I have been having an issue where it refuses to even read the file for some reason:
string line;
ifstream menuFile("menu.txt");
if (menuFile.is_open())
{
int i = 0;
while (getline(menuFile, line));
{
cout << line << endl;
istringstream iss(line);
iss >> dataList[i].menuItem >> dataList[i].menuPrice;
/*iss >> dataList[i].menuPrice;*/
i++;
}
}
else
{
cout << "Unable to open file.";
}
When I run it, it doesn't spit out "Unable to open file.", and when I trace it, it does enter the if loop, but it just doesn't read it. Besides that problem though, I want to know if this code would work in the way I want it to, and if doesn't, how to solve this problem.
EDIT: When I run it, it outputs what the last line of the file said, that being "Tea 0.75". The full file is as follows:
Plain Egg 1.45
Bacon and Egg 2.45
Muffin 0.99
French Toast 1.99
Fruit Basket 2.49
Cereal 0.69
Coffee 0.50
Tea 0.75
EDIT 2: For some reason, the following code goes straight to the last line, Tea 0.75, and I have no idea why, shouldn't the getline just go line by line until the last line(?):
string line;
int index;
ifstream menuFile("menu.txt");
if (menuFile.is_open())
{
while (getline(menuFile, line));
{
cout << line << endl;
index = line.find_last_of(' ');
cout << index << endl;
}
}
EDIT 3: Above code has a semicolon at the end of the while loop, no wonder it was just ending on the last line, ughhh.
- Grab the line into a string.
- Get the position of the last separator.
- Your text is a substring of the line until the position of the separator.
- Your number is a substring of the line from the position of the separator. You'll need to convert it to double first (and you should check for errors).
[Demo]
#include <iostream> // cout
#include <string> // find_last_of, getline, stod
int main()
{
std::string line{};
while (std::getline(std::cin, line))
{
auto pos{line.find_last_of(' ')};
auto text{line.substr(0, pos)};
auto number{std::stod(line.substr(pos))};
std::cout << "text = " << text << ", number = " << number << "\n";
}
}
// Outputs
//
// text = Plain Egg, number = 1.45
// text = Bacon and Egg, number = 2.45
// text = Muffin, number = 0.99
// text = French Toast, number = 1.99
// text = Fruit Basket, number = 2.49
// text = Cereal, number = 0.69
// text = Coffee, number = 0.5
// text = Tea, number = 0.75
//
A more robust solution taking into account @Dúthomhas' comments:
- Trims the right hand side of the string before finding the last separator.
- Catches
std::stod
exceptions.
This solution detects:
- Blank lines.
- Lines without texts.
- Lines without numbers.
- Incorrect number formats.
[Demo]
#include <boost/algorithm/string.hpp>
#include <fmt/core.h>
#include <iostream> // cout
#include <string> // find_last_of, getline, stod
int main()
{
std::string line{};
while (std::getline(std::cin, line))
{
try
{
boost::trim_right(line);
auto pos{line.find_last_of(' ')};
auto text{line.substr(0, pos)};
auto number{std::stod(line.substr(pos))};
std::cout << "text = " << text << ", number = " << number << "\n";
}
catch (const std::exception&)
{
std::cout << fmt::format("* Error: invalid line '{}'\n", line);
}
}
}
// Outputs:
//
// text = Plain Egg, number = 1.45
// text = Bacon and Egg, number = 2.45
// text = Muffin, number = 0.99
// text = French Toast, number = 1.99
// * Error: invalid line ''
// * Error: invalid line 'Fruit Basket'
// * Error: invalid line '0.75'
// * Error: invalid line 'Coffee blah'