如何从文本文件中读取值和数组

How to read values and arrays from text file

我知道如何使用 ifstream 等读取文件。我只是被困在这个任务中,我有一个充满常量的头文件和一个包含 3 个变量的文本文件(预算、酒店类型、[事件 1、事件 2、... , 事件n]).

#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++,谢谢任何帮助的人!

编辑:我认为常量头文件对此不是必需的。我很抱歉

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

首先用','分割每一行 return 数组有 2 个元素

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

那么你应该得到 "[" , "]" 之间的字符串并再次被分割,并且 return 多长度数组

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

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

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

并且您需要填充 std::vector<Entity> 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 包装提供的数据,但代码将适用于任何提供的输入流。

如果我对你的问题理解正确,这里有一个解决方案可以解决你的问题。 根据您的文件,您需要三个变量:

  1. 预算,这是一维数组
  2. 酒店类型,也是一维数组
  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} ...}

让我知道我是否在正确的轨道上,以便我们可以继续实施...

EDIT

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

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

我试图通过代码中的注释来描述这个解决方案。它基本上只是定义流运算符,以便能够 read/write 来自任何流的数据。

#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]]