在遇到特定分隔符后读取4行c ++

时间:2019-07-29 15:33:04

标签: c++

我一直在尝试创建一个可以用作收银机的简单程序。假定从文件中读取以下内容: - 名称, - 价钱, -告诉它是水果还是蔬菜, -卡路里

我认为最好的方法是检测标识号(类似于条形码),然后读取4行并在“:”定界符后得到4个字符串。

这是我创建的txt文件:

# Vegetables #

Iden number             :   11
Name                    :   Carrot
Price       [zl/kg]     :   2
Group                   :   Vegetable
Calories    [cal/100 g] :   33

Nr Iden                 :   12
Name                    :   Tomato
Price       [zl/kg]     :   4
Group                   :   Vegetable
Calories    [cal/100 g] :   20

Iden number             :   13
Name                    :   Cucumber
Price       [zl/kg]     :   1
Group                   :   Vegetable
Calories    [cal/100 g] :   14

# Fruits #

Iden number             :   21
Name                    :   Apple
Price       [zl/kg]     :   2
Group                   :   Fruit
Calories    [cal/100 g] :   52

Iden number             :   22
Name                    :   Orange
Price       [zl/kg]     :   4
Group                   :   Fruit
Calories    [cal/100 g] :   47

Iden number             :   23
Name                    :   Kiwi
Price       [zl/kg]     :   1
Group                   :   Fruit
Calories    [cal/100 g] :   60

这里是检测分隔符并忽略空行或以“#”开头的代码的代码。但我不知道在检测到identy_number之后如何只读取以下4行。

    int main()
{
  string line;
  ifstream plik ("baza_danych_produktow.txt");
  if (plik.is_open())
  {
    while ( getline (plik,line) )
    {
    line.erase(std::remove_if(line.begin(), line.end(), ::isspace),line.end());

     if(line[0] == '#' || line.empty()){ // if line starts with # or is empty - ignore
            continue;
        }

    auto delimiterPos = line.find(":");
    auto name = line.substr(0, delimiterPos);
    std::string value = line.substr(delimiterPos + 1);
    cout << value;
    cout << endl;
    }
    plik.close();
  }

  else cout << "Unable to open file";

  return 0;
}

我的代码在不为空或不以“#”开头的文件的每一行中显示“:”定界符之后的每个字符串。

以下是输出:

11
Carrot
2
Vegetable
33
12
Tomato
4
Vegetable
20
13
Cucumber
1
Vegetable
13
21
Apple
2
Fruit
52
22
Orange
4
Fruit
47
23
Kiwi
1
Fruit
60

您能帮我吗,例如 input:11 的输出看起来像这样吗?

Carrot
2
Vegetable
33

最诚挚的问候。

2 个答案:

答案 0 :(得分:0)

如果找到ID,您可以在while循环内调用另一个getline 4次

#include <algorithm>
#include <iostream>
#include <sstream>
#include <string>
using std::cout;
using std::endl;
using std::stringstream;
using std::string;

int main()
{
    string id = "22";
    string line;

    stringstream plik ("# Vegetables #\n\nIden number             :   11\nName                    :   Carrot\nPrice       [zl/kg]     :   2\nGroup                   :   Vegetable\nCalories    [cal/100 g] :   33\n\nNr Iden                 :   12\nName                    :   Tomato\nPrice       [zl/kg]     :   4\nGroup                   :   Vegetable\nCalories    [cal/100 g] :   20\n\nIden number             :   13\nName                    :   Cucumber\nPrice       [zl/kg]     :   1\nGroup                   :   Vegetable\nCalories    [cal/100 g] :   14\n\n# Fruits #\n\nIden number             :   21\nName                    :   Apple\nPrice       [zl/kg]     :   2\nGroup                   :   Fruit\nCalories    [cal/100 g] :   52\n\nIden number             :   22\nName                    :   Orange\nPrice       [zl/kg]     :   4\nGroup                   :   Fruit\nCalories    [cal/100 g] :   47\n\nIden number             :   23\nName                    :   Kiwi\nPrice       [zl/kg]     :   1\nGroup                   :   Fruit\nCalories    [cal/100 g] :   60\n");

    if (/*plik.is_open()*/ true) {
        while (getline(plik, line)) {
            line.erase(std::remove_if(line.begin(), line.end(), ::isspace), line.end());

            if (line[0] == '#' || line.empty()) { // if line starts with # or is empty - ignore
                continue;
            }

            auto delimiterPos = line.find(":");
            auto name = line.substr(0, delimiterPos);
            if (name == "Idennumber") {
                std::string currentId = line.substr(delimiterPos + 1);
                for (unsigned short i{ 0 }; i < 4; ++i) {
                    getline(plik, line);
                    auto delimiterPos = line.find(":");
                    auto name = line.substr(0, delimiterPos);
                    std::string value = line.substr(delimiterPos + 1);

                    if (currentId == id) {
                        cout << value << '\n';
                    }
                }
            }
        }
        /*plik.close();*/
    }
    else
        cout << "Unable to open file";

    return 0;
}

答案 1 :(得分:0)

我想向您介绍一个更“现代”的C ++解决方案。使用算法和“更多” OO(面向对象)方法。

在我看来,面向对象设计的关键是将数据及其方法放到一个对象(类)中。

例如,一个产品具有一些数据成员。它具有如何读写数据的智慧,并且有责任。因此,任何第三方都不应从此类对象中读取/写入数据。

如果您采用这种方法,则可以使用fileStream >> product;阅读完整的产品记录。而已。一个班轮。而且更直观

与打印相同。就像通过std::cout << number;打印数字一样,对产品也是如此。为什么不写std::cout << product

在下面的代码中,我添加了一个功能测试,正是该测试。这非常简单。

此外,我还读取了内存中的所有数据,为您提供了更全面的示例。该代码包含大量注释,应该易于理解。

请参阅:

#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
#include <string>
#include <sstream>
#include <iomanip>

// This is a file. It is the same as reading a file from a disk
std::istringstream inputFile{ R"(# Vegetables #

Iden number : 11
Name : Carrot
Price[zl / kg] : 2
Group : Vegetable
Calories[cal / 100 g] : 33

Nr Iden : 12
Name : Tomato
Price[zl / kg] : 4
Group : Vegetable
Calories[cal / 100 g] : 20

Iden number : 13
Name : Cucumber
Price[zl / kg] : 1
Group : Vegetable
Calories[cal / 100 g] : 14

# Fruits #

Iden number : 21
Name : Apple
Price[zl / kg] : 2
Group : Fruit
Calories[cal / 100 g] : 52

Iden number : 22
Name : Orange
Price[zl / kg] : 4
Group : Fruit
Calories[cal / 100 g] : 47

Iden number : 23
Name : Kiwi
Price[zl / kg] : 1
Group : Fruit
Calories[cal / 100 g] : 60
)" };

// Create Some shorter name
constexpr std::string::size_type NOK = std::string::npos;
// This is, what we are searching for in the product data
const std::vector<std::string_view> identifier{ "Name","Price","Group","Calories" };

// Our product class. Keep data and methods together in on object
struct Product
{
    Product() : data(identifier.size()) {}
    // The iden number
    std::string iden{};
    // All data. Since verything is treated as a string, we will put this in a vector
    std::vector<std::string> data;

    // This class knows how to read and write its data. This is the know how of this objec´t. It belongs to here.
    // Overwrite extractor operator >>
    friend std::istream& operator >> (std::istream& is, Product& p);
    // Overwrite inserter operator <<
    friend std::ostream& operator << (std::ostream& os, const Product& p);

};

// The inserter operator for a product. Very simple. Print all available data
std::ostream& operator << (std::ostream& os, const Product& p)
{
    // First the iden number
    os << "\n" << std::left << std::setw(15) << "Iden number" << p.iden << '\n';
    // And then all data
    for (size_t index = 0U; (index < p.data.size()) && (index < identifier.size()); ++index) 
        os << std::setw(15) << identifier[index] << p.data[index] << '\n';
    return os;
}

// The products extractor operator. That is a little bit more complex
std::istream& operator >> (std::istream& is, Product& p)
{
    std::string line{};
    size_t pos{ 0 }; size_t index{ 0 }; 

    // We will read lines from the input stream, until we are done
    while (getline(is, line)) {
        // First, search for a string that conatins "Iden" or "Nr Iden"
        pos = line.find(':'); // Look if the line has a double colon
        // Search
        if (((line.find("Iden") == 0) || line.find("Nr Iden" == 0)) && (pos != NOK)) {

            // Ok, we found a line that contains "Iden" or "Nr Iden" 
            std::istringstream iss(line.substr(pos + 1));
            iss >> p.iden; // Read the data into our product internal variable

            // Now continue to read lines. Either 4 lines or until some read error
            while ((index < identifier.size()) && getline(is, line)) {
                // Check the position of the double colon
                pos = line.find(":");
                // And now find the expected search string given in identifier{ "Name","Price","Group","Calories" }
                if ((line.find(identifier[index]) != NOK) && (pos != NOK)) {
                    // if Foundm, then put the data into our product internal data variable
                    std::istringstream iss(line.substr(pos + 1));
                    iss >> p.data[index];
                }
                ++index;
            }
            break;  // After we read on product, we will stop reading lines
        }
        // else, if the line does not match our expected value, then ignore it and read next line
    }
    return is;
 }


void test()
{
    Product product{};
    // What we want to show
    std::string searchID{ "22" };
    // Read all products
    while (inputFile >> product) {

        // If we found what we were looking for 
        if (product.iden == searchID) {
            // Then show result
            std::cout << product << "\n\n";
            break; // stop further reading
        }
    }
}


 int main()
 {
     test(); inputFile.seekg(0);;

     // Define variable that holds all products
     // Define variable with range constructor that will copy the data from somewhere begin to somewhere end
     // Somewhere begin is the istream iterator that reads from the beginning of the file
     // Somewhere end is the istream iterator that reads until end of file
     // Since the extractor operator >> of the product has been overwritten, the istream_iteratir will call this operatir with the istream
     std::vector<Product> products{std::istream_iterator<Product>(inputFile), std::istream_iterator<Product>() };

     // For debug purposes. Print all products
     std::cout << "\nThis is the complete list of products that we have read from the file:\n\n";
     // We use the copy operator. Meaning, we copy the range products.begin/products.end to somewhere
     // The somewhere is the std ostream_iterator which will simple print the given data to std::cout
     // Since we have overwritten the inserter operator << of the product, this operator will be called for each element in the products list
     std::copy(products.begin(), products.end(), std::ostream_iterator<Product>(std::cout, "\n"));

     // Ask the user, what product he wants to see
     std::cout << "\n\nWhat product do you want to see? Enter Iden number:  ";
     std::string searchString{};
     // Get that value from the user
     std::cin >> searchString;

     // And now find it in the list of products. All product in the products list will be check. Their iden will be compared with the search string
     std::vector<Product>::iterator iter = std::find_if(products.begin(), products.end(), [&searchString](const Product & p) { return p.iden == searchString; });

     // If we could find something
     if (iter != products.end()) 
         // Show some text and the data. We show the data be inserting *iter in the std::cout stream. The will call the product inserter operator
         std::cout << "\n\nFound product with Iden (" << searchString << ")   -->\n" << *iter << '\n';
      else
         // Nothing could be found
         std::cout << "\n\nProduct with Iden (" << searchString << ")  NOT found in proct list\n";

     return 0;
 }

请查看“测试”功能的简单程度。而且,如果您对产品进行更改,它仍然可以使用。因为功能隐藏在产品所属的产品中。它被封装了。