Как читать значения и массивы из текстового файла - PullRequest
0 голосов
/ 01 ноября 2018

Я знаю, как читать файл с помощью 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 ++, спасибо всем, кто помогает!

Edit: я не думаю, что файл заголовка констант необходим для этого. Мои извинения

Ответы [ 5 ]

0 голосов
/ 01 ноября 2018

Я пытался описать это решение комментариями в коде. Он в основном просто определяет потоковые операторы для возможности чтения / записи данных из любого потока.

#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]]
0 голосов
/ 01 ноября 2018

Если я правильно понимаю ваш вопрос, вот решение для вашей проблемы. Согласно вашему файлу, вам нужны три переменные:

  1. бюджет, который представляет собой 1-й массив
  2. hotelType, который также является 1-м массивом
  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;
}
0 голосов
/ 01 ноября 2018

Сначала разделите каждую строку на ',' этот массив возвращает 2 элемента

первый элемент бюджета и второй элемент это hotelType [event1, event2,…, eventn]

тогда вы должны получить строку между "[", "]" и снова разделить на, и этот возвращаемый массив будет иметь мульти-длину

0 голосов
/ 01 ноября 2018

Возможны разные подходы к чтению отформатированных данных в 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 упаковку предоставленных данных, но код будет работать с любым предоставленным входным потоком.

0 голосов
/ 01 ноября 2018

это строка, верно? почему вы не пытаетесь разделить запятую, превращая в массивы? Вы можете читать с каждой строкой буфера, а затем разделять запятыми (снимая скобки) и сохраняя значения.

...