先頭へ戻る

マルチバイト文字 解答ページ | Programming Place Plus 新C++編

Programming Place Plus トップページ新C++編マルチバイト文字

先頭へ戻る

このページの概要

このページは、練習問題の解答例や解説のページです。



解答・解説

問題1 (基本★)

蔵書リストのプログラムに、メモリ上にあるすべての本のデータを削除する cコマンドを追加してください。


メモリ上の本のデータとは、std::vector の変数 books に格納されているデータということです。データがメモリ上にあるということと、ファイルに書き出されているということの違いはきちんと意識しましょう。

プログラムの変更点は2箇所だけです。1つは使用できるコマンドを提示する部分のメッセージの追加です。

        std::cout << "----------------------------\n"
                  << "コマンドを入力してください。\n"
                  << "a: 本を登録する。\n"
                  << "d: 本を削除する。\n"
                  << "c: すべての本を削除する。\n"
                  << "p: リストを確認する。\n"
                  << "r: ファイルから読み込む。\n"
                  << "w: ファイルに書き込む。\n"
                  << "e: 終了する。\n"
                  << "----------------------------\n";

どこに追加しても構いませんし、文面も自由にしていいですが、ともかく cコマンドを追加しました。

もう1つは、コマンドごとの処理を記述するコードの追加です。else if が並んでいるところに、新たに cコマンドを処理する else if を追加します。

        else if (command == "c") {
            // すべての本を削除する

            books.clear();
            std::cout << "削除しました。\n";
        }

本のデータをすべて削除するためには、std::vector の中身を空にすればいいので clear関数を呼ぶだけです。

問題2 (基本★★)

蔵書リストのプログラムで、価格として負数や整数でない値が入力されたときに、不適切な入力であることを伝えて入力しなおさせるようにしてください。


たとえば、aコマンドの処理のところを次のように書き換えます。

        if (command == "a") {
            // 本を登録する

            Book book {};
            std::istringstream iss {};
            std::string tmp {};

            std::cout << "書名を入力してください。\n";
            std::getline(std::cin, book.title);

            std::cout << "著者名を入力してください。\n";
            std::getline(std::cin, book.author);

            std::cout << "価格を入力してください。\n";
            while (true) {
                std::getline(std::cin, tmp);
                iss.str(tmp);
                iss >> book.price;
                if (!iss || book.price < 0) {
                    std::cout << "価格は 0以上の整数で入力してください。\n";
                    iss.clear();
                }
                else {
                    break;
                }
            }

            std::cout << "評価を入力してください。\n";
            std::getline(std::cin, tmp);
            iss.clear();
            iss.str(tmp);
            iss >> book.evaluate;

            if (!std::cin) {
                std::cout << "入力内容に不備があります。\n";
            }
            else {
                books.push_back(book);
                std::cout << "登録しました。\n";
            }
        }

入力された文字列を、std::istringstream を使って book.price に整数として取り出した直後に、値をチェックする if文を入れます。また、不適切な入力だったときにやりなおさせるように、while のループにしています。

整数としてみなせない内容であったために、book.price への取り出しに失敗した場合は、!iss が true になります。また、負数の場合を book.price < 0 で判定しています。どちらかに引っかかった場合はループを継続し、どちらにも引っかからない場合は正常な入力とみなして、break文でループから抜け出しています。

問題3 (応用★★)

蔵書リストのプログラムで、ファイルへの保存を行わずに eコマンドを入力したとき、保存せずに終了していいか確認するようにしてください。ユーザーが終了しない意思を示した場合は、コマンド入力に戻すようにしてください。


メモリ上の本のデータに何かしらの変更を加えたときに true になる bool型の変数 isChanged を追加します。

    bool isChanged {false};

aコマンドで本を追加したとき、dコマンドで本を削除したとき、cコマンドですべての本を削除したときに、isChanged に true を代入します。一方、rコマンドでファイルから読み込んだとき、wコマンドでファイルに書き込んだときには isChanged を false に戻します。

                books.push_back(book);
                isChanged = true;
                std::cout << "登録しました。\n";



                books.erase(it);
                isChanged = true;
                std::cout << "削除しました。\n";



            books.clear();
            isChanged = true;
            std::cout << "削除しました。\n";



            isChanged = false;
            std::cout << "読み込みました。\n";



            isChanged = false;
            std::cout << "書き込みました。\n";

そして、eコマンドの処理のところで、isChanged が true の場合に確認を行うようにします。

        else if (command == "e") {
            // 終了する

            if (isChanged) {
                std::cout << "変更した内容をファイルに書き込んでいませんが、終了してよろしいですか? (Y/N)\n";
                std::string s {};
                std::cin >> s;
                if (s != "Y" && s != "y") {
                    continue;
                }
            }

            std::cout << "終了します。\n";
            return 0;
        }

確認の仕方は自由です。ここでは Y か N(Yes と No の意味)を入力させ、Y なら終了、N ならやりなおしにしています(入力しやすいように小文字でも受け付けるようにしています)。どちらでもない入力がなされた場合は、N の扱いになるように、if (s != "Y" && s != "y") という判定にして、明確に Yes の意思を示さなければ終了しないようにしています。

問題4 (応用★★)

蔵書リストのプログラムに検索機能を追加してください。


使用できるコマンドを提示する部分のメッセージを追加します。

        std::cout << "----------------------------\n"
                  << "コマンドを入力してください。\n"
                  << "a: 本を登録する。\n"
                  << "d: 本を削除する。\n"
                  << "c: すべての本を削除する。\n"
                  << "p: リストを確認する。\n"
                  << "st: 書名で検索する。\n"
                  << "sa: 著者名で検索する。\n"
                  << "sp: 価格で検索する。\n"
                  << "se: 評価で検索する。\n"
                  << "r: ファイルから読み込む。\n"
                  << "w: ファイルに書き込む。\n"
                  << "e: 終了する。\n"
                  << "----------------------------\n";

それぞれのコマンドの処理を追加します。コードの内容はほとんど同じです。

        else if (command == "st") {
            // 書名で検索する

            std::cout << "書名を入力してください。\n";
            std::string title {};
            std::getline(std::cin, title);

            for (auto& book : books) {
                if (book.title == title) {
                    std::cout << "書名: " << book.title << "\n"
                              << "著者名: " << book.author << "\n"
                              << "価格: " << book.price << "\n"
                              << "評価: " << book.evaluate << "\n"
                              << "\n";                  
                }
            }
        }
        else if (command == "sa") {
            // 著者名で検索する

            std::cout << "著者名を入力してください。\n";
            std::string author {};
            std::getline(std::cin, author);

            for (auto& book : books) {
                if (book.author == author) {
                    std::cout << "書名: " << book.title << "\n"
                              << "著者名: " << book.author << "\n"
                              << "価格: " << book.price << "\n"
                              << "評価: " << book.evaluate << "\n"
                              << "\n";                  
                }
            }
        }
        else if (command == "sp") {
            // 価格で検索する

            std::cout << "価格を入力してください。\n";
            std::string tmp {};
            std::getline(std::cin, tmp);
            std::istringstream iss {tmp};
            int price {};
            iss >> price;
            if (!iss || price < 0) {
                std::cout << "入力内容に不備があります。\n";
            }
            else {
                for (auto& book : books) {
                    if (book.price >= price) {
                        std::cout << "書名: " << book.title << "\n"
                                  << "著者名: " << book.author << "\n"
                                  << "価格: " << book.price << "\n"
                                  << "評価: " << book.evaluate << "\n"
                                  << "\n";                  
                    }
                }
            }
        }
        else if (command == "se") {
            // 評価で検索する

            std::cout << "評価を入力してください。\n";
            std::string tmp {};
            std::getline(std::cin, tmp);
            std::istringstream iss {tmp};
            int evaluate {};
            iss >> evaluate;
            if (!iss) {
                std::cout << "入力内容に不備があります。\n";
            }
            else {
                for (auto& book : books) {
                    if (book.evaluate >= evaluate) {
                        std::cout << "書名: " << book.title << "\n"
                                  << "著者名: " << book.author << "\n"
                                  << "価格: " << book.price << "\n"
                                  << "評価: " << book.evaluate << "\n"
                                  << "\n";                  
                    }
                }
            }
        }


ここまでのすべての改造を取り込むと、蔵書リストのプログラムは次のようになります。

#include <algorithm>
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>

int main()
{
    constexpr auto booklist_path = "booklist.txt";

    struct Book {
        std::string    title;      // 書名
        std::string    author;     // 著者名
        int            price;      // 価格
        int            evaluate;   // 評価
    };

    std::vector<Book> books {};
    bool isChanged {false};

    while (true) {
        std::cout << "----------------------------\n"
                  << "コマンドを入力してください。\n"
                  << "a: 本を登録する。\n"
                  << "d: 本を削除する。\n"
                  << "c: すべての本を削除する。\n"
                  << "p: リストを確認する。\n"
                  << "st: 書名で検索する。\n"
                  << "sa: 著者名で検索する。\n"
                  << "sp: 価格で検索する。\n"
                  << "se: 評価で検索する。\n"
                  << "r: ファイルから読み込む。\n"
                  << "w: ファイルに書き込む。\n"
                  << "e: 終了する。\n"
                  << "----------------------------\n";

        std::string command {};
        std::getline(std::cin, command);
        if (command == "a") {
            // 本を登録する

            Book book {};
            std::istringstream iss {};
            std::string tmp {};

            std::cout << "書名を入力してください。\n";
            std::getline(std::cin, book.title);

            std::cout << "著者名を入力してください。\n";
            std::getline(std::cin, book.author);

            std::cout << "価格を入力してください。\n";
            while (true) {
                std::getline(std::cin, tmp);
                iss.str(tmp);
                iss >> book.price;
                if (!iss || book.price < 0) {
                    std::cout << "価格は 0以上の整数で入力してください。\n";
                    iss.clear();
                }
                else {
                    break;
                }
            }

            std::cout << "評価を入力してください。\n";
            std::getline(std::cin, tmp);
            iss.clear();
            iss.str(tmp);
            iss >> book.evaluate;
            if (!iss) {
                std::cout << "入力内容に不備があります。\n";
            }
            else {
                books.push_back(book);
                isChanged = true;
                std::cout << "登録しました。\n";
            }
        }
        else if (command == "d") {
            // 本を削除する

            std::cout << "書名を入力してください。\n";
            std::string title {};
            std::getline(std::cin, title);

            auto it = std::find_if(std::cbegin(books), std::cend(books), [title](Book e){ return e.title == title; });
            if (it == std::cend(books)) {
                std::cout << "指定された本は登録されていません。\n";
            }
            else {
                books.erase(it);
                isChanged = true;
                std::cout << "削除しました。\n";
            }
        }
        else if (command == "c") {
            // すべての本を削除する

            books.clear();
            isChanged = true;
            std::cout << "削除しました。\n";
        }
        else if (command == "p") {
            // リストを確認する

            for (auto& book : books) {
                std::cout << "書名: " << book.title << "\n"
                          << "著者名: " << book.author << "\n"
                          << "価格: " << book.price << "\n"
                          << "評価: " << book.evaluate << "\n"
                          << "\n";
            }
        }
        else if (command == "st") {
            // 書名で検索する

            std::cout << "書名を入力してください。\n";
            std::string title {};
            std::getline(std::cin, title);

            for (auto& book : books) {
                if (book.title == title) {
                    std::cout << "書名: " << book.title << "\n"
                              << "著者名: " << book.author << "\n"
                              << "価格: " << book.price << "\n"
                              << "評価: " << book.evaluate << "\n"
                              << "\n";                  
                }
            }
        }
        else if (command == "sa") {
            // 著者名で検索する

            std::cout << "著者名を入力してください。\n";
            std::string author {};
            std::getline(std::cin, author);

            for (auto& book : books) {
                if (book.author == author) {
                    std::cout << "書名: " << book.title << "\n"
                              << "著者名: " << book.author << "\n"
                              << "価格: " << book.price << "\n"
                              << "評価: " << book.evaluate << "\n"
                              << "\n";                  
                }
            }
        }
        else if (command == "sp") {
            // 価格で検索する

            std::cout << "価格を入力してください。\n";
            std::string tmp {};
            std::getline(std::cin, tmp);
            std::istringstream iss {tmp};
            int price {};
            iss >> price;
            if (!iss || price < 0) {
                std::cout << "入力内容に不備があります。\n";
            }
            else {
                for (auto& book : books) {
                    if (book.price >= price) {
                        std::cout << "書名: " << book.title << "\n"
                                  << "著者名: " << book.author << "\n"
                                  << "価格: " << book.price << "\n"
                                  << "評価: " << book.evaluate << "\n"
                                  << "\n";                  
                    }
                }
            }
        }
        else if (command == "se") {
            // 評価で検索する

            std::cout << "評価を入力してください。\n";
            std::string tmp {};
            std::getline(std::cin, tmp);
            std::istringstream iss {tmp};
            int evaluate {};
            iss >> evaluate;
            if (!iss) {
                std::cout << "入力内容に不備があります。\n";
            }
            else {
                for (auto& book : books) {
                    if (book.evaluate >= evaluate) {
                        std::cout << "書名: " << book.title << "\n"
                                  << "著者名: " << book.author << "\n"
                                  << "価格: " << book.price << "\n"
                                  << "評価: " << book.evaluate << "\n"
                                  << "\n";                  
                    }
                }
            }
        }
        else if (command == "r") {
            // ファイルから読み込む

            std::ifstream ifs(booklist_path);
            if (!ifs) {
                std::cout << "ファイルが開けません。\n";
                continue;
            }

            // メモリ上の本のデータを消す
            books.clear();

            while (!ifs.eof()) {
                Book book {};
                std::istringstream iss {};
                std::string tmp {};

                std::getline(ifs, book.title);
                if (book.title.empty()) {
                    break;
                }

                std::getline(ifs, book.author);

                std::getline(ifs, tmp);
                iss.str(tmp);
                iss >> book.price;
                iss.clear();

                std::getline(ifs, tmp);
                iss.str(tmp);
                iss >> book.evaluate;

                books.push_back(book);
            }

            isChanged = false;
            std::cout << "読み込みました。\n";
        }
        else if (command == "w") {
            // ファイルに書き込む

            std::ofstream ofs(booklist_path);
            if (!ofs) {
                std::cout << "ファイルが開けません。\n";
                continue;
            }

            for (auto& book : books) {
                ofs << book.title << "\n"
                    << book.author << "\n"
                    << book.price << "\n"
                    << book.evaluate << "\n";
            }

            ofs.close();
            if (!ofs) {
                std::cout << "書き込みに失敗しました。\n";
                continue;
            }

            isChanged = false;
            std::cout << "書き込みました。\n";
        }
        else if (command == "e") {
            // 終了する

            if (isChanged) {
                std::cout << "変更した内容をファイルに書き込んでいませんが、終了してよろしいですか? (Y/N)\n";
                std::string s {};
                std::cin >> s;
                if (s != "Y" && s != "y") {
                    continue;
                }
            }

            std::cout << "終了します。\n";
            return 0;
        }
        else {
            // 無効なコマンド
            continue;
        }
    }
}


参考リンク



更新履歴




はてなブックマーク に保存 Pocket に保存 Facebook でシェア
Twitter でツイート Twitter をフォロー LINE で送る
rss1.0 取得ボタン RSS 管理者情報 プライバシーポリシー