Загрузка данных


#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <algorithm>
#include <limits>
#include <iomanip>
#include <cctype>
using namespace std;

struct Cinema {
    string film;
    string time;
    double price;
    int    viewers;
};

// ==================== ВАЛИДАЦИЯ ====================

bool vName(const string& s) {
    if (s.empty()) return false;
    for (char c : s)
        if (!isalnum((unsigned char)c) && c != ' ' && c != '-' && c != '_')
            return false;
    return true;
}

bool vTime(const string& s) {
    if (s.size() != 5 || s[2] != ':') return false;
    for (int i : {0, 1, 3, 4})
        if (!isdigit((unsigned char)s[i])) return false;
    return stoi(s.substr(0, 2)) < 24 && stoi(s.substr(3, 2)) < 60;
}

bool vPrice(double p)  { return p >= 0 && p <= 100000; }
bool vView(int v)      { return v >= 0 && v <= 1000000; }

// ==================== БЕЗОПАСНЫЙ ВВОД ====================

int getInt(const string& prompt, bool (*v)(int) = nullptr) {
    int x;
    while (true) {
        cout << prompt;
        if (cin >> x && (!v || v(x))) {
            cin.ignore(10000, '\n');
            return x;
        }
        cout << "Ошибка ввода.\n";
        cin.clear();
        cin.ignore(10000, '\n');
    }
}

double getDouble(const string& prompt, bool (*v)(double) = nullptr) {
    double x;
    while (true) {
        cout << prompt;
        if (cin >> x && (!v || v(x))) {
            cin.ignore(10000, '\n');
            return x;
        }
        cout << "Ошибка ввода.\n";
        cin.clear();
        cin.ignore(10000, '\n');
    }
}

string getStr(const string& prompt, bool (*v)(const string&) = nullptr) {
    string s;
    while (true) {
        cout << prompt;
        getline(cin, s);
        if (!v || v(s)) return s;
        cout << "Ошибка ввода.\n";
    }
}

// ==================== ОПЕРАЦИИ ====================

Cinema makeItem() {
    Cinema c;
    c.film    = getStr("Название фильма: ", vName);
    c.time    = getStr("Время (HH:MM): ",   vTime);
    c.price   = getDouble("Цена билета: ",  vPrice);
    c.viewers = getInt("Зрителей: ",        vView);
    return c;
}

void addAll(vector<Cinema>& a) {
    int n = getInt("Сколько записей добавить? ", [](int x){ return x > 0 && x <= 1000; });
    while (n--) {
        cout << "--- Запись ---\n";
        a.push_back(makeItem());
    }
}

void show(const vector<Cinema>& a) {
    if (a.empty()) {
        cout << "Массив пуст.\n";
        return;
    }
    cout << string(70, '-') << "\n"
         << left << setw(25) << "Фильм"
                 << setw(8)  << "Время"
                 << setw(10) << "Цена"
                 << setw(10) << "Зрители" << "\n"
         << string(70, '-') << "\n";

    for (auto& c : a)
        cout << left << setw(25) << c.film
                     << setw(8)  << c.time
                     << setw(10) << fixed << setprecision(2) << c.price
                     << setw(10) << c.viewers << "\n";

    cout << string(70, '-') << "\n";
}

void sortAll(vector<Cinema>& a) {
    sort(a.begin(), a.end(), [](const Cinema& x, const Cinema& y) {
        string s = x.film, t = y.film;
        transform(s.begin(), s.end(), s.begin(), ::tolower);
        transform(t.begin(), t.end(), t.begin(), ::tolower);
        return s < t;
    });
    cout << "Отсортировано.\n";
}

void search(const vector<Cinema>& a) {
    if (a.empty()) {
        cout << "Массив пуст.\n";
        return;
    }
    string k = getStr("Название для поиска: ", vName);
    transform(k.begin(), k.end(), k.begin(), ::tolower);

    bool found = false;
    for (auto& c : a) {
        string n = c.film;
        transform(n.begin(), n.end(), n.begin(), ::tolower);
        if (n == k) {
            cout << c.film << " | " << c.time << " | "
                 << c.price << " | " << c.viewers << "\n";
            found = true;
        }
    }
    if (!found) cout << "Не найдено.\n";
}

void editItem(vector<Cinema>& a) {
    if (a.empty()) {
        cout << "Массив пуст.\n";
        return;
    }
    show(a);
    int i = getInt("Номер для изменения: ",
                   [&](int x){ return x >= 1 && (size_t)x <= a.size(); });
    a[i - 1] = makeItem();
}

void removeItem(vector<Cinema>& a) {
    if (a.empty()) {
        cout << "Массив пуст.\n";
        return;
    }
    show(a);
    int i = getInt("Номер для удаления: ",
                   [&](int x){ return x >= 1 && (size_t)x <= a.size(); });
    a.erase(a.begin() + i - 1);
}

// ==================== ФАЙЛ ====================

string esc(const string& s) {
    if (s.find_first_of(",\"") == string::npos) return s;
    string r = "\"";
    for (char c : s)
        r += (c == '"') ? "\"\"" : string(1, c);
    return r + "\"";
}

void save(const vector<Cinema>& a, const string& fn = "cinema.csv") {
    ofstream f(fn);
    if (!f) {
        cout << "Не удалось открыть файл.\n";
        return;
    }
    f << "Фильм,Время,Цена,Зрители\n";
    for (auto& c : a)
        f << esc(c.film) << ","
          << esc(c.time) << ","
          << fixed << setprecision(2) << c.price << ","
          << c.viewers << "\n";
    cout << "Сохранено в " << fn << "\n";
}

// ==================== МЕНЮ ====================

int main() {
    setlocale(LC_ALL, "Russian");

    vector<Cinema> a;
    int c;

    do {
        cout << "\n1.Ввод  2.Сортировка  3.Поиск  4.Изменение  "
                "5.Удаление  6.Вывод  7.Сохранить  0.Выход\n> ";

        if (!(cin >> c)) {
            cin.clear();
            cin.ignore(10000, '\n');
            continue;
        }
        cin.ignore(10000, '\n');

        switch (c) {
            case 1: addAll(a);     break;
            case 2: sortAll(a);    break;
            case 3: search(a);     break;
            case 4: editItem(a);   break;
            case 5: removeItem(a); break;
            case 6: show(a);       break;
            case 7: save(a);       break;
            case 0: save(a); cout << "Выход.\n"; break;
            default: cout << "Неверный пункт.\n";
        }
    } while (c != 0);
}