有什么简单的方法可以从文件中读取一行,将第一个文本部分拆分为一个字符串,然后将最后一个数字部分拆分为一个浮点数?
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?
我有一个问题,我一直找不到解决的好方法,主要是因为我对 C++ 比较陌生,但对编程并不陌生。我有一个包含多行的文件,其中之一是:
Plain Egg 1.45
我需要能够读取该行并将第一部分“Plain Egg”拆分为一个字符串,然后将最后一部分 1.45 拆分为一个浮点数,然后对其余部分执行此操作线。以下是我到目前为止的一些代码,但我遇到了一个问题,由于某种原因它甚至拒绝读取文件:
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.";
}
当我 运行 它时,它不会吐出“无法打开文件。”,当我跟踪它时,它确实进入了 if 循环,但它只是不读取它。不过除了这个问题,我想知道这段代码是否能按照我想要的方式工作,如果不能,如何解决这个问题。
编辑:当我 运行 它时,它输出文件最后一行所说的内容,即“Tea 0.75”。完整文件如下:
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
编辑 2:出于某种原因,以下代码直接进入最后一行,Tea 0.75,我不知道为什么,getline 不应该逐行直到最后一行(?):
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;
}
}
编辑 3:上面的代码在 while 循环的末尾有一个分号,难怪它只是在最后一行结束,呃。
您可以对给定的输入执行此操作,方法是迭代字符串以找到浮点值开始的索引。然后抓取每个部分的子字符串并将值转换为浮点数。
#include <iostream>
using namespace std;
int main()
{
string s = "Bacon and Egg 2.45";
int l = 0;
string food;
float val = 0.0;
for (int i = 0; i < s.length(); i++)
{
if(isdigit(s[i]))
{
l = i;
break;
}
}
food = s.substr(0,l);
val = stof(s.substr(l,s.length()));
cout << food << endl;
cout << val;
}
- 将行抓取成字符串。
- 获取最后一个分隔符的位置。
- 您的文本是该行的子字符串,直到分隔符的位置。
- 您的号码是分隔符所在行的子串。您需要先将其转换为 double(并且您应该检查错误)。
#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
//
考虑到@Dúthomhas 的评论的更强大的解决方案:
- 在找到最后一个分隔符之前修剪字符串的右侧。
- 捕获
std::stod
个异常。
此解决方案检测到:
- 空行。
- 没有文字的行。
- 没有数字的行。
- 数字格式不正确。
#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'
有点笨手笨脚:使用寻找字符串中最后一个 space 的相同想法,但左右修剪 spaces。不好的是,虽然它有很多代码,但它仍然不能以任何形式使用 unicode。
// Right trim the line
while(!line.empty()) {
if (isspace(line.back())) {
line.pop_back();
}
}
// Find the last space
size_t pos = line.find_last_of(" \t");
if (pos == std::string::npos) {
// Bad line: no spaces or only spaces
handle_it();
}
// Get the price
double price = 0.0;
try {
size_t end_pos = 0;
price = std::stod(line.substr(pos), &end_pos);
if ((pos + end_pos) != line.length()) {
// Another bad format: garbage at the end
handle_it();
}
} catch (...) {
// Another bad format
handle_it();
}
// Left trim the item
size_t skip = 0;
while(skip > pos && isspace(line[skip])) {
skip++;
}
if (skip == pos) {
// Another bad format: spaces + price
handle_it();
}
// Right trim the item
// we know that we have at leas one non-space
pos--;
while(isspace(line[pos])) {
pos--;
}
std::string item = line.substr(skip, pos + 1);
我有一个问题,我一直找不到解决的好方法,主要是因为我对 C++ 比较陌生,但对编程并不陌生。我有一个包含多行的文件,其中之一是:
Plain Egg 1.45
我需要能够读取该行并将第一部分“Plain Egg”拆分为一个字符串,然后将最后一部分 1.45 拆分为一个浮点数,然后对其余部分执行此操作线。以下是我到目前为止的一些代码,但我遇到了一个问题,由于某种原因它甚至拒绝读取文件:
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.";
}
当我 运行 它时,它不会吐出“无法打开文件。”,当我跟踪它时,它确实进入了 if 循环,但它只是不读取它。不过除了这个问题,我想知道这段代码是否能按照我想要的方式工作,如果不能,如何解决这个问题。
编辑:当我 运行 它时,它输出文件最后一行所说的内容,即“Tea 0.75”。完整文件如下:
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
编辑 2:出于某种原因,以下代码直接进入最后一行,Tea 0.75,我不知道为什么,getline 不应该逐行直到最后一行(?):
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;
}
}
编辑 3:上面的代码在 while 循环的末尾有一个分号,难怪它只是在最后一行结束,呃。
您可以对给定的输入执行此操作,方法是迭代字符串以找到浮点值开始的索引。然后抓取每个部分的子字符串并将值转换为浮点数。
#include <iostream>
using namespace std;
int main()
{
string s = "Bacon and Egg 2.45";
int l = 0;
string food;
float val = 0.0;
for (int i = 0; i < s.length(); i++)
{
if(isdigit(s[i]))
{
l = i;
break;
}
}
food = s.substr(0,l);
val = stof(s.substr(l,s.length()));
cout << food << endl;
cout << val;
}
- 将行抓取成字符串。
- 获取最后一个分隔符的位置。
- 您的文本是该行的子字符串,直到分隔符的位置。
- 您的号码是分隔符所在行的子串。您需要先将其转换为 double(并且您应该检查错误)。
#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
//
考虑到@Dúthomhas 的评论的更强大的解决方案:
- 在找到最后一个分隔符之前修剪字符串的右侧。
- 捕获
std::stod
个异常。
此解决方案检测到:
- 空行。
- 没有文字的行。
- 没有数字的行。
- 数字格式不正确。
#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'
有点笨手笨脚:使用寻找字符串中最后一个 space 的相同想法,但左右修剪 spaces。不好的是,虽然它有很多代码,但它仍然不能以任何形式使用 unicode。
// Right trim the line
while(!line.empty()) {
if (isspace(line.back())) {
line.pop_back();
}
}
// Find the last space
size_t pos = line.find_last_of(" \t");
if (pos == std::string::npos) {
// Bad line: no spaces or only spaces
handle_it();
}
// Get the price
double price = 0.0;
try {
size_t end_pos = 0;
price = std::stod(line.substr(pos), &end_pos);
if ((pos + end_pos) != line.length()) {
// Another bad format: garbage at the end
handle_it();
}
} catch (...) {
// Another bad format
handle_it();
}
// Left trim the item
size_t skip = 0;
while(skip > pos && isspace(line[skip])) {
skip++;
}
if (skip == pos) {
// Another bad format: spaces + price
handle_it();
}
// Right trim the item
// we know that we have at leas one non-space
pos--;
while(isspace(line[pos])) {
pos--;
}
std::string item = line.substr(skip, pos + 1);