Skip to content

bmstu-iu8-cpp-sem-3/lab-01-parser

Repository files navigation

Лабораторная работа № 1

Задание

Реализовать утилиту табличного вывода массива данных, хранящихся в файле формата JSON.

В качестве аргумента утилите передается путь в к файлу, который в ключе items
содержит массив объектов, каждый объект из которых имеет следующие ключи:
name - фамилия и имя студента (строчный тип)
group - номер группы (строчный/целочисленный тип)
avg - средний балл (строчный/целочисленный/вещественный тип)
debt - список задолженностей (строчный/перечислительный тип)

Иллюстрация

Рассмотрим на примере students.json файл содержащий описание 3 студентов.

{
  "items": [
    {
      "name": "Ivanov Petr",
      "group": "1",
      "avg": "4.25",
      "debt": null
    },
    {
      "name": "Sidorov Ivan",
      "group": 31,
      "avg": 4,
      "debt": "C++"
    },
    {
      "name": "Pertov Nikita",
      "group": "IU8-31",
      "avg": 3.33,
      "debt": [
        "C++",
        "Linux",
        "Network"
      ]
    }
  ],
  "_meta": {
    "count": 3
  }
}

И иллюстрацию того, что должна вывести программа после обработки данного файла.

# ./parser students.json

| name          | group  | avg  | debt          |
|---------------|--------|------|---------------|
| Ivanov Petr   | 1      | 4.25 | null          |
|---------------|--------|------|---------------|
| Sidorov Ivan  | 31     | 4.00 | C++           |
|---------------|--------|------|---------------|
| Pertov Nikita | IU8-31 | 3.33 | 3 items       |
|---------------|--------|------|---------------|

Требования

При разработке утилиты parser необходимо учесть следующие моменты:

  • Реализовать проверку входных данных:
    • наличия аргумента, содержащего путь к файлу
    • существования файла
    • items is array
    • _meta.count == len(items)
  • Вывод ошибок должен быть информативным
  • При написание тестов учесть сценарии с различными типами для полей (group, avg, debt)

Подсказки

Для парсинга JSON файла стоит воспользоваться библиотекой nlohmann_json, подключив ее через пакетный менеджер Hunter.

// include/student.hpp

struct Student {
    std::string name;
    std::any group;
    std::any avg;
    std::any debt;
}
// sources/student.cpp

using nlohmann::json;

void from_json(const json& j, student_t& s) {

    s.name = get_name(j.at("group"));
    s.group = get_group(j.at("group"));
    s.avg = get_avg(j.at("avg"));
    s.debt = get_group(j.at("debt"));
}

auto get_name(const json& j) -> std::string {
    return j.get<std::string>();
}

auto get_debt(const json& j) -> std::any {
    if (j.is_null())
        return nullptr;
    else if (j.is_string())
        return j.get<std::string>();
    else
        return j.get<std::vector<std::string> >();
}

auto get_avg(const json& j) -> std::any {
    if (j.is_null())
        return nullptr;
    else if (j.is_string())
        return j.get<std::string>();
    else if (j.is_number_float())
        return j.get<double>();
    else
        return j.get<std::size_t>();
}

auto get_group(const json& j) -> std::any {
    if (j.is_string())
        return = j.get<std::string>();
    else
        return j.get<std::size_t>();
}
// sources/main.cpp

int main() {
    //...
    std::ifstream file{jsonPath};
    if (!file) {
        throw std::runtime_error{"unable to open json: " + jsonPath};
    }

    json data;
    file >> data;

    std::vector<student_t> students;
    for (auto const& item : data.at("items")) {
        auto student = item.get<student_t>()
        students.push_back(student);
    }
    //...
    print(students, std::cout);
}

void print(const std::vector<student_t>& students, std::ostream& os) {

    //...
    for (auto const& student : students) {
        print(student, os);
    }
}
void print(const student_t& student, std::ostream& os) {
    //...
    if (student.debt.type() == typeid(std::nullptr_t)) {
        os << "null";
    } else if (student.debt.type() == typeid(std::string)) {
        os << std::any_cast<std::string>(student.debt);
    } else {
        os
          << std::any_cast<std::vector<std::string> >(student.debt).size()
          << " items";
    }
}