有什么简单的方法可以从文件中读取一行,将第一个文本部分拆分为一个字符串,然后将最后一个数字部分拆分为一个浮点数?

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(并且您应该检查错误)。

[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
//   

考虑到@Dúthomhas 的评论的更强大的解决方案:

  • 在找到最后一个分隔符之前修剪字符串的右侧。
  • 捕获 std::stod 个异常。

此解决方案检测到:

  • 空行。
  • 没有文字的行。
  • 没有数字的行。
  • 数字格式不正确。

[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'

有点笨手笨脚:使用寻找字符串中最后一个 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);