简体   繁体   English

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

[英]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.我有一个问题一直没能找到解决的好方法,主要是因为我对 C++ 比较陌生,但对编程并不陌生。 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.我需要能够读取该行并将第一部分“Plain Egg”拆分为一个字符串,然后将最后一部分 1.45 拆分为一个浮点数,然后对这些行的 rest 执行此操作。 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.当我运行它时,它不会吐出“无法打开文件。”,当我跟踪它时,它确实进入了 if 循环,但它只是不读取它。 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".编辑:当我运行它时,它会输出文件最后一行所说的内容,即“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(?):编辑2:出于某种原因,以下代码直接进入最后一行,Tea 0.75,我不知道为什么,getline 不应该只是 go 一行一行,直到最后一行(?):

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.编辑3:上面的代码在while循环的末尾有一个分号,难怪它只是在最后一行结束,呃。

  • Grab the line into a string.将线抓取成一个字符串。
  • Get the position of the last separator.获取最后一个分隔符的 position。
  • Your text is a substring of the line until the position of the separator.您的文本是分隔符的 position 之前的行的 substring。
  • Your number is a substring of the line from the position of the separator.您的号码是 position 的行的 substring 分隔符。 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:考虑到@Dúthomhas 的评论,一个更强大的解决方案:

  • Trims the right hand side of the string before finding the last separator.在找到最后一个分隔符之前修剪字符串的右侧。
  • Catches std::stod exceptions.捕获std::stod异常。

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& ex)
        {
            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'

You can do this for your given inputs by iterating the string to find the index at which the float value begins.您可以通过迭代字符串以查找浮点值开始的索引来对给定的输入执行此操作。 Then grab the substring for each part and cast the value to a float.然后获取每个部分的 substring 并将值转换为浮点数。

#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;
}

Somewhat heavy handed:有点沉重:

  // 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);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM