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

时间:2018-11-01 07:10:04

标签: c++ arrays fstream

我知道如何使用ifstream等读取文件。我只是停留在此任务上,在那里我有一个充满常量的头文件和一个包含3个变量(budget,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 ++,谢谢任何帮助过的人!

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

5 个答案:

答案 0 :(得分:1)

使用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));
}

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

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

您可以在此处查看此代码的运行情况:https://rextester.com/MDZDG18083

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

答案 1 :(得分: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;
}

答案 2 :(得分:0)

是一个字符串,对不对?为什么不尝试用逗号分割成数组呢? 您可以读取每行的缓冲行,然后按逗号分割(除去括号)并保存值。

答案 3 :(得分:0)

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

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

这时,您应该在“ [”,“]”之间得到一个字符串,并再次将其分割,然后返回具有多长度的数组

答案 4 :(得分:0)

我试图通过代码中的注释来描述此解决方案。它基本上只是定义了流运算符,以便能够从任何流中读取/写入数据。

forEach

示例输出:

#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;
}
相关问题