仅从文件中读取特定数据...如果传递字符串值,则从文件中读取所有内容 c++98

To read only specific data from file... if string value is passed else to read everything from file c++98

我有一个名为 bird.lst 的文件。我正在尝试读取其内容并存储数据映射数据结构。

我想在哪里阅读具体的鸟类信息,

  1. 当字符串值传递给std::string find = "pigeon";时,将得到pigeon的信息。 (使用当前代码
  2. 如果将空值传递给字符串std::string find = " ";,那么应该可以获取鸟类的所有信息。(不工作

我有点卡住了,不知道如何继续。欢迎提出建议,提前致谢。

我已经提到过 std::string find 传递空值或带有预期输出的鸟值的示例...

bird.cpp

#include <fstream>
#include <iostream>
#include <map>
#include <sstream>
#include <string>
#include <vector>
#include <utility>

typedef std::pair<std::string,std::string> attribute_pair;
typedef std::vector<attribute_pair> attribute_vector;
typedef std::map<std::string,attribute_vector> bird_map;

int main()
{
    std::ifstream file("bird.lst");
    std::string find = " ";
    bird_map birds;
    std::string key;
    while(std::getline(file,key))
    {
        std::size_t pos = key.find(find);
        attribute_vector attributes;
        std::string value;
        if(pos != std::string::npos && key.substr(pos) == find) {

        while(std::getline(file,value))
        {
            // in case it has windows encoding with end-of-line = \r\n
            if (!value.empty() &&
                value[value.size()-1] == '\r')
            {
                value.erase(value.size() - 1);
            }

            // if we found the empty string
            if(value.empty())
            {
                break;
            }

            // now split the value into an attribute and a flag
            attribute_pair attribute;
            std::istringstream ss(value);
            ss >> attribute.first >> attribute.second;
            if(attribute.first != "vaccinated" && attribute.first != "babies" && attribute.first != "sale") {
            // save the value into the vector
               attributes.push_back(attribute);
             }
        }
        // save the bird into the map
        birds[key] = attributes;
    }
}
    // now print the data we collected
    for(bird_map::iterator bird = birds.begin();
        bird != birds.end();
        bird++)
    {
        std::cout << bird->first << "\n";
        for(attribute_vector::iterator attribute = bird->second.begin();
            attribute != bird->second.end();
            attribute++)
        {
            std::cout << "   " << attribute->first
                      << "   " << attribute->second
                      << "\n";
        }
        std::cout << "\n";
    }

    return 0;
}

bird.lst

parrot
vaccinated  yes
eat         yes
babies      no
fly         yes
sale        no

pigeon
vaccinated  yes
eat         yes
fly         yes
babies      yes
sale        yes

duck
vaccinated  yes
eat         yes
fly         no
sale        yes
babies      no

flammingo
vaccinated  yes
eat         yes
fly         yes
sale        no
babies      no

eagle
vaccinated  yes
eat         yes
babies      no
fly         yes

std::string find="duck"; 使用现有代码时。

duck
   eat   yes
   fly   no

std::string find=" "; 它应该从哪里获取所有鸟类的数据时

duck
   eat   yes
   fly   no

eagle
   eat   yes
   fly   yes

flammingo
   eat   yes
   fly   yes

parrot
   eat   yes
   fly   yes

pigeon
   eat   yes
   fly   yes

我又添加了一个函数读取完整的一只鸟信息并在循环中调用它。然后根据要求在find参数中传递空字符串或匹配bird以获取特定数据。

#include <fstream>
#include <iostream>
#include <map>
#include <sstream>
#include <string>
#include <vector>
#include <utility>

typedef std::pair<std::string,std::string> attribute_pair;
typedef std::vector<attribute_pair> attribute_vector;
typedef std::map<std::string,attribute_vector> bird_map;

void readBird(std::ifstream &file, std::string &key, std::string &find, bird_map &birds)
{
           attribute_vector attributes;
           std::string value;
           while(std::getline(file,value))
           {
              // in case it has windows encoding with end-of-line = \r\n
              if (!value.empty() &&
                 value[value.size()-1] == '\r')
              {
                  value.erase(value.size() - 1);
              }

              // if we found the empty string
              if(value.empty())
              {
                 break;
              }

            // now split the value into an attribute and a flag
            attribute_pair attribute;
            std::istringstream ss(value);
            ss >> attribute.first >> attribute.second;
            if(attribute.first != "vaccinated" && attribute.first != "babies" && attribute.first != "sale") {
            // save the value into the vector
               attributes.push_back(attribute);
             }
              birds[key] = attributes;
          }
}

int main()
{
    std::ifstream file("bird.lst");
    std::string find = "";
    std::string key;

    bird_map birds;
    while(std::getline(file,key))
    {
        if(find.empty())
        {
            readBird(file, key, find, birds);
        }
        else
        {
            std::size_t pos = key.find(find);
            if(pos != std::string::npos && key.substr(pos) == find)
            {
                readBird(file, key, find, birds);
            }
        }
     }
    // now print the data we collected
    for(bird_map::iterator bird = birds.begin();
        bird != birds.end();
        bird++)
    {
        std::cout << bird->first << "\n";
        for(attribute_vector::iterator attribute = bird->second.begin();
            attribute != bird->second.end();
            attribute++)
        {
            std::cout << "   " << attribute->first
                      << "   " << attribute->second
                      << "\n";
        }
        std::cout << "\n";
    }

    return 0;
}

" " 不是空字符串,"" 是。无论如何,您也不会在搜索之前检查空字符串。

无论如何,当 find() 找不到匹配项时,您将完全跳过内部 while 循环,因此不会跳过当前鸟类的信息。所以下一个外循环迭代误解那些未读的属性,就好像它们是鸟的名字一样,这是错误的。

我建议编写一个函数,可以一次从文件中读取一只鸟的 完整 信息,然后在循环中调用该函数。在每次迭代中,如果搜索字符串确实为空,或者它与当前鸟的名字相匹配,则根据需要使用该鸟的信息。在后一种情况下,您可以打破循环。

您作为答案发布的代码是实现此类功能的良好尝试,但代码仍然存在问题。除了它甚至没有解决跳过不匹配鸟类属性读取的问题之外,您还以一种尴尬的方式在 main()readBird() 之间分配了读取和处理鸟类详细信息的责任。 main() 读取每只鸟的名字,然后 readBird() 读取鸟的属性并将鸟插入 map唯一读取完整鸟、名称和属性的责任应该只在readBird()内,然后是main() 应该根据需要决定如何处理每只输出的 complete 鸟。

话虽如此,请尝试更像这样的东西:

#include <fstream>
#include <iostream>
#include <sstream>
#include <map>
#include <string>
#include <vector>
#include <utility>

typedef std::pair<std::string, std::string> attribute_pair;
typedef std::vector<attribute_pair> attribute_vector;
typedef std::map<std::string, attribute_vector> bird_map;

bool readLine(std::istream &in, std::string &s)
{
    if (!std::getline(in, s)) return false;
    if ((!s.empty()) && (s.back() == '\r')) s.pop_back();
    return true;
}

bool readBird(std::istream &in, std::string &name, attribute_vector &attributes)
{
    name.clear();
    attributes.clear();

    std::string value;
    attribute_pair attribute;

    do {
        if (!readLine(in, value)) return false;
    }
    while (value.empty());

    name = value;

    while (readLine(in, value) && !value.empty()) {
        std::istringstream iss(value);
        if ((iss >> attribute.first) && ((attribute.first != "vaccinated") && (attribute.first != "babies") && (attribute.first != "sale"))) {
           iss >> attribute.second;
           attributes.push_back(attribute);
        }
    }

    return true;
}

int main()
{
    std::ifstream file("bird.lst");
    std::string name, find;
    attribute_vector attributes;
    bird_map birds;

    std::cout << "What would you like to search for? (leave blank for all):" << endl;
    std::getline(std::cin, find);

    while (readBird(file, name, attributes))
    {
        if (find.empty() || (name.find(find) != std::string::npos))
            birds[name] = attributes;
    }

    for(bird_map::iterator bird = birds.begin();
        bird != birds.end();
        ++bird)
    {
        std::cout << bird->first << "\n";
        for(attribute_vector::iterator attribute = bird->second.begin();
            attribute != bird->second.end();
            ++attribute)
        {
            std::cout << "   " << attribute->first << "   " << attribute->second << "\n";
        }
        std::cout << "\n";
    }

    return 0;
}