【问题标题】:How to read values and arrays from text file如何从文本文件中读取值和数组
【发布时间】:2018-11-01 07:10:04
【问题描述】:

我知道如何使用 ifstream 等读取文件。我只是被困在这个任务中,我有一个充满常量的头文件和一个包含 3 个变量(预算、hotelType、[event1、event2、...、eventn)的文本文件])。

#ifndef CONSTANTS_H_
#define CONSTANTS_H_


const string nameMap[] = { "Opening", "Soccer 1", "Soccer 2", "Soccer 3",
        "Track and Field 1", "Track and Field 2", "Track and Field 3",
        "Track and Field 4", "Swimming 1", "Swimming 2", "Gymnastics 1",
        "Gymnastics 2", "Basketball 1", "Basketball 2", "Closing" };
const int eventPriceMap[] = { 2000, 80, 160, 500, 80, 100, 120, 140, 100, 100, 60, 100,
        150, 300, 800 };

const int eventDateMap[] = { 0, 3, 6, 9, 1, 2, 3, 4, 5, 6, 7, 8, 5, 7, 9 };

const int eventQuota[] = {60, 47, 30, 22, 50, 52, 42, 25, 37, 20, 43, 34, 35, 30, 40};

const int hotelPriceMap[] = {160, 210, 320};

const int hotelQuota[] ={20, 25, 30};// per day

const int MAXEVENTS = 10;

const int MAXREQUESTS = 150;

const int NUMBEROFEVENTS = 15;

const int NUMBEROFDAYS = 10;

#endif /* CONSTANTS_H_ */
9020,4[2,0,5,14,10,4,3,13,1]
7805,5[13,3,12,12,0,9,7,10,6,1]
7075,5[3,2,4,9,7,0,1,5,6,14]
7679,4[0,4,14,1,3,12,5,10]
6356,3[7,3]
6874,5[14,0,4,10,9,3]
4715,4[9]
4784,5[11]
4321,3[5,3,8,9]
6469,5[7,6,6,14,12,5,2]
4838,4[1,2]
4103,3[14]
5904,5[5,4,6]
5775,3[10,14,14,8,7,3,4]
7070,4[1,4,6,11,13,3,2,5,14]
4605,3[6,10,1,8,7,3,3]
7484,4[11,5,14,2,6,7,8,1,0]

在另一个文件中,我将如何阅读此文本文档并将其保存到 Budget、hotelType 和 [events] 中。我完全不知道我还在学习 c++,感谢任何帮助的人!

编辑:我不认为常量头文件是必要的。我的道歉

【问题讨论】:

    标签: c++ arrays fstream


    【解决方案1】:

    如果我正确理解了您的问题,以下是解决您问题的解决方案。 根据您的文件,您需要三个变量:

    1. 预算,即一维数组
    2. hotelType,也是一维数组
    3. 事件,可以是二维数组

    因此,基于此,解决方案可能是:

    budget[]  = {9020,7805,7075,7679,6356,6874,4715 ...}
    hotelType[] = {4,5,5,4,3,5 ...}
    events[][] = {{2,0,5,14,10,4,},{13,3,12,12,0,9,7,10,6,1},{3,2,4,9,7,0,1,14} ...}
    

    如果我走在正确的轨道上,请告诉我,以便我们继续实施......

    编辑

    第一个解决方案,使用数组:

    #include <iostream>
    #include <string>
    #include <fstream>
    
    int main()
    {
       std::ifstream infile("file.txt");
       std::string line;
       int budget[100], hotelType[100], events[100][100], index = 0;
       while (std::getline(infile, line)){
           std::string num;
           int i = 0;
           for( ; i < line.length(); i++){
                if(line[i] != ',' && line[i] != '[' && line[i] != ']')
                    num += line[i];
                else{
                    budget[index] = std::stoi(num);
                    num = "";
                    break;
                }
           }
           i++;
           hotelType[index] = std::stoi(line.substr(i, 1));
           i++; i++;
           for(int j = 0; i < line.length(); i++){
                if(line[i] != ',' && line[i] != '[' && line[i] != ']')
                    num += line[i];
                else{
                    events[index][j] = std::stoi(num);
                    num = "";
                    j++;
                }
           }
           index++;
       }
       for(int i = 0; i < index; i++){
           std::cout<< i + 1 << "th: ";
           std::cout<< "\tBudget    : " << budget[i] << std::endl;
           std::cout<< "\tHotel Type: " << hotelType[i] << std::endl;
           std::cout<< "\tEvents    : " << std::endl;
           for(int j = 0; j < 5; j++)
               std::cout<< "\t\t" << events[i][j] << std::endl;
       }
       return 0;
    }
    

    【讨论】:

    • 它应该显示一些东西。最后一个for-loop 应该打印文件中变量保存的所有内容。可能您需要将文件名 file.txt 更改为您保存在计算机上的确切文件名。
    【解决方案2】:

    在 C++ 中读取格式化数据可能有不同的方法。最直接的是使用输入流的功能,你说你很熟悉。它可以为您读取整数,您只需手动跳过所有分隔符。

    假设您将数据存储为这些结构的数组:

    struct Entity
    {
        int budget;
        int hotel_type;
        std::vector<int> events;
    };
    

    您需要填充std::vector&lt;Entity&gt; entities。如果您的数据被传递到标准输入,解析代码将是:

    while (cin) {
        Entity entity;
        char separator;
        cin >> entity.budget >> separator >> entity.hotel_type >> separator;
    
        while (cin && separator != ']') {
            int event;
            cin >> event >> separator;
            entity.events.push_back(event);
        }
    
        if (cin)
            entities.push_back(std::move(entity));
    }
    

    这个简单的实现不会检查格式是否严格符合预期。 IE。它只是将分隔字符读入separator 变量。您可以添加检查它确实是逗号或方括号。

    请注意最后的if (cin)。如果我们尝试从没有数据的流中读取数据(即它已经耗尽),则内部eofbit 标志将设置为流。我们通过简单地提供字符串变量作为条件来检查它,因为它定义了operator bool(),它为我们检查eofbit标志(以及其他一些标志)。我们需要在读取后进行检查,以确保读取成功。

    你可以在这里看到这个代码:https://rextester.com/MDZDG18083

    在此演示中,我使用自定义 std::stringstream 包装提供的数据,但代码将适用于任何提供的输入流。

    【讨论】:

      【解决方案3】:

      这是一个字符串,对吧?为什么不尝试通过逗号转换为数组来拆分? 您可以每行读取缓冲行,然后用逗号分隔(删除括号)并保存值。

      【讨论】:

        【解决方案4】:

        首先用','分割每一行 返回包含 2 个元素的数组

        第一个元素是预算 第二个元素是hotelType[event1, event2, ..., eventn]

        那么你应该在 "[" , "]" 之间得到字符串,然后再由 分割,返回多长度数组

        【讨论】:

          【解决方案5】:

          我尝试在代码中用 cmets 来描述这个解决方案。它基本上只是定义了流操作符,以便能够从任何流中读取/写入数据。

          #include <iostream>
          #include <fstream>
          #include <string>
          #include <vector>
          #include <ios>
          #include <sstream>
          #include <stdexcept>
          
          // create an alias for a number of events using a standard container
          // for int's, std::vector<int>
          using EventList = std::vector<int>;
          
          // add an input stream operator for our EventList to be able to read
          // and split strings looking like  [int,int,...,int]
          std::istream& operator>>(std::istream& is, EventList& el) {
              std::string tmp; // a temporary string
              el.clear();      // remove any existing events
          
              if(std::getline(is, tmp)) { // read until end-of-line
                  // check that we got [ and ]
                  if(tmp.size()<2 || tmp[0] != '[' || tmp[tmp.size()-1] != ']') {
                      // wrong format, set the input streams failbit
                      is.setstate(std::ios::failbit);
                  } else {
                      // remove the first and last character  [ and ]
                      tmp = tmp.substr(1, tmp.size()-2);
                      // put the string in a string stream to be able
                      // to use std::getline with a delimiter
                      std::stringstream ss(tmp);
                      // loop until the stringstream is empty
                      while( std::getline(ss, tmp, ',') ) {
                          // tmp should now be a string of digits
                          // use stoi to convert the string to an int
                          try {
                              int an_int = std::stoi(tmp);
                              // put the int at the back of our EventList
                              el.emplace_back(an_int);
                          } catch(const std::invalid_argument& ex) {
                              // the conversion to an int failed
                              // set the input streams failbit
                              is.setstate(std::ios::failbit);
                          }
                      }
                  }
              } else {
                  // getline failed, set the failbit on the stream
                  is.setstate(std::ios::failbit);
              }
              return is;
          }
          
          // add an output stream operator for EventList to be able to output
          // it in the same format as it was read
          std::ostream& operator<<(std::ostream& os, const EventList& el) {
              os << "[";
              if(el.size()) { // check that we have events to stream
                  // create an iterator that points at the first element
                  EventList::const_iterator it = el.begin();
                  // dereference the iterator to get the int it points to
                  // and stream that int
                  os << *it;
                  ++it; // step to the next event
                  // loop until the iterator points beyond the last element
                  // in the EventList
                  for(;it!=el.end(); ++it) {
                      // prepend each event with a comma
                      os << "," << *it;
                  }
              }
              os << "]";
              return os;
          }
          
          // here's an operator for a vector of EventList's for convenience
          // it follows the same pattern as the operator above
          std::ostream& operator<<(std::ostream& os, const std::vector<EventList>& vel) {
              os << "[";
              if(vel.size()) {
                  std::vector<EventList>::const_iterator it = vel.begin();
                  os << *it;
                  ++it;
                  for(;it!=vel.end(); ++it) {
                      os << " " << *it;
                  }
              }
              os << "]";
              return os;
          }
          
          // one line in your file      int,int[int...]
          // broken down into a struct
          struct OneDataLine {
              int budget;
              int hotelType;
              EventList events;   // using the alias created above
          
              // the default constructor with initialization of members
              OneDataLine() :
                  budget(0),
                  hotelType(0),
                  events()
              {}
              // declaring stream operators as friends, allowing them to operate
              // on the objects members. this is not really necessary
              // since this struct has all members public but if you later decide
              // to make them private, this will come in handy
              friend std::istream& operator>>(std::istream&, OneDataLine&);
              friend std::ostream& operator<<(std::ostream&, const OneDataLine&);
          };
          
          // an input stream operator for reading one data line
          std::istream& operator>>(std::istream& is, OneDataLine& d) {
              char separator;
              is >> d.budget >> separator >> d.hotelType;
              if(separator != ',') {
                  // if the separator between budget and hotelType is not
                  // a comma, set the input stream in a failed state
                  is.setstate(std::ios::failbit);
              } else {
                  // we should now only have the events part left on
                  // the line. stream it to the EventList for which we
                  // have already added an input stream operator
                  is >> d.events;
              }
              return is;
          }
          
          // an output stream operator for writing one data line
          std::ostream& operator<<(std::ostream& os, const OneDataLine& d) {
              // int's have built-in stream operators
              // and we have also added an output stream operator for
              // EventList so streaming becomes easy
              os << d.budget << "," << d.hotelType << d.events;
              return os;
          }
          
          // USAGE: progname datafile1 ... datafileX
          int main(int argc, char* argv[]) {
              // convert C style main() parameters to a C++ container.
              // we use std::vector again, but this time for storing
              // strings
              std::vector<std::string> args(argv+1, argv+argc);
              // yet another vector, but this is for storing data lines
              std::vector<OneDataLine> all_data_lines;
          
              // Reading part
          
              // loop over the input parameters to main()
              for(const std::string& file : args) {
                  std::fstream fs(file); // open file for reading
                  // loop over the opened file for as long as the
                  // filestream's failbit isn't set
                  while(fs) {
                      // a temporary instance of OneDataLine
                      OneDataLine tmp;
                      // stream from the open file to our temporary
                      fs >> tmp;
                      // if the failbit still isn't set, move the
                      // content of the temporary variable into
                      // our vector of data lines
                      if(fs) all_data_lines.emplace_back(std::move(tmp));
                  }
                  // the filestream will be automatically closed
                  // when it goes out of scope
              }
          
              // Writing part
          
              // loop over all the data lines we've collected and
              // stream to cout. we could just as well stream to
              // a file opened for writing
              for(const OneDataLine& line : all_data_lines) {
                  // stream the complete data line using our own output
                  // stream operator for OneDataLine
                  std::cout << line << "\n";
          
                  // stream individual members too
                  std::cout << " budget   : " << line.budget << "\n";
                  std::cout << " hotelType: " << line.hotelType << "\n";
                  std::cout << " events   : " << line.events << "\n";
                  // and stream each event separately
                  std::cout << "          [\n";
                  for(const int& ev : line.events) {
                      std::cout << "            " << ev << "\n";
                  }
                  std::cout << "          ]\n";
              }
          
              // Creating containers for each category
              std::vector<int> budgets;
              std::vector<int> hotelTypes;
              std::vector<EventList> event_lists;
              // loop through the collected data and put each member in
              // the container for its category
              for(const OneDataLine& line : all_data_lines) {
                  budgets.push_back(line.budget);
                  hotelTypes.push_back(line.hotelType);
                  event_lists.push_back(line.events);
              }
              // Output categorized containers
          
              // here we use EventList's (std::vector<int>'s) output stream operator
              std::cout << "budgets    : " << budgets << "\n";
              std::cout << "hotelTypes : " << hotelTypes << "\n";
              // and here we use our convenience output stream operator for
              // a vector of EventList
              std::cout << "event_lists: " << event_lists << "\n";
              return 0;
          }
          

          样本输出:

          % progname datafile
          [...skipping to the end...]
          
          7484,4[11,5,14,2,6,7,8,1,0]
           budget   : 7484
           hotelType: 4
           events   : [11,5,14,2,6,7,8,1,0]
                    [
                      11
                      5
                      14
                      2
                      6
                      7
                      8
                      1
                      0
                    ]
          budgets    : [9020,7805,7075,7679,6356,6874,4715,4784,4321,6469,4838,4103,5904,5775,7070,4605,7484]
          hotelTypes : [4,5,5,4,3,5,4,5,3,5,4,3,5,3,4,3,4]
          event_lists: [[2,0,5,14,10,4,3,13,1] [13,3,12,12,0,9,7,10,6,1] [3,2,4,9,7,0,1,5,6,14] [0,4,14,1,3,12,5,10] [7,3] [14,0,4,10,9,3] [9] [11] [5,3,8,9] [7,6,6,14,12,5,2] [1,2] [14] [5,4,6] [10,14,14,8,7,3,4] [1,4,6,11,13,3,2,5,14] [6,10,1,8,7,3,3] [11,5,14,2,6,7,8,1,0]]
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-03-27
            • 2012-06-10
            • 2015-01-05
            相关资源
            最近更新 更多