MochiuWiki : SUSE, EC, PCB
案内
メインページ
最近の更新
おまかせ表示
MediaWiki についてのヘルプ
ツール
リンク元
関連ページの更新状況
特別ページ
ページ情報
We ask for
Donations
検索
個人用ツール
ログイン
Toggle dark mode
名前空間
ページ
議論
表示
閲覧
ソースを閲覧
履歴を表示
C++の応用 - YAMLのソースを表示
提供: MochiuWiki : SUSE, EC, PCB
←
C++の応用 - YAML
あなたには「このページの編集」を行う権限がありません。理由は以下の通りです:
この操作は、次のグループのいずれかに属する利用者のみが実行できます:
管理者
、new-group。
このページのソースの閲覧やコピーができます。
== 概要 == YAML (YAML Ain't Markup Language) は、人間にとって読み書きしやすいデータシリアライゼーション形式である。<br> 設定ファイル、データ交換、データ保存等、様々な用途で使用されている。<br> <br> YAMLの特徴を以下に示す。<br> * 可読性が高い *: インデントを使用して構造を表現するため、人間が読みやすい形式である。 * 豊富なデータ型 *: 文字列、数値、ブール値、リスト、マップ (辞書) 等の基本的なデータ型をサポートしている。 * 柔軟性 *: 複雑なデータ構造も表現できる。 * コメントのサポート *: <u>#</u>を使用して、コメントを記述することができる。 * 参照と別名 *: データの再利用や循環参照が可能である。 <br> YAMLの使用するメリットを以下に示す。<br> * 設定ファイルに適している *: 人間が読み書きしやすいため、アプリケーションの設定ファイルとしてよく使用されている。 * データ交換に適している *: JSONの代替として使用でき、より読みやすい形式でデータを表現できる。 * 柔軟性が高い *: 複雑なデータ構造も簡単に表現できる。 * 多くの言語でサポートされている *: 多くのプログラミング言語にYAMLパーサーが存在する。 <br> YAMLは、可読性の高さと柔軟性から、多くの開発者に好まれている。<br> 特に、設定ファイルやデータ交換の用途で広く使用されており、多くのモダンなアプリケーションやフレームワークでYAMLが採用されている。<br> <br> C++では、YAMLの処理によく使用されるライブラリの1つにyaml-cppライブラリが存在する。<br> <br><br> == YAMLの基本的な構造 == <u>※注意</u><br> * インデントが重要 *: スペースを使用してインデントを行い、一貫性を保つ必要がある。 * コロンの後にはスペースが必要 *: "<キー>: <値>"のように、コロンの後にスペースを入れる必要がある。 * 文字列のクォート *: 特殊文字を含む場合や曖昧さを避けたい場合は、文字列をクォートで囲むことができる。 <br> <syntaxhighlight lang="yaml"> # This is a comment --- # Document start # スカラー値 (文字列, 数値, ブール値) name: John Doe age: 30 is_student: false # リスト (ハイフンを使用) hobbies: - reading - traveling - photography # マッピング (キー: 値の形式) address: street: 123 Main St city: Anytown country: USA # 複雑なデータ構造 (リストとマッピングの組み合わせ) employees: - name: Alice position: Developer skills: - Python - JavaScript - name: Bob position: Designer skills: - Photoshop - Illustrator # 複数行の文字列 description: > This is a long description that spans multiple lines. The > symbol preserves newlines but removes extra whitespace. # 複数行の文字列 (> と | を使用) code_sample: | def hello_world(): print("Hello, World!") # アンカー ("&") と エイリアス ("*") を使用したデータの再利用 defaults: &defaults timeout: 30 retries: 3 production: <<: *defaults host: production.example.com development: <<: *defaults host: dev.example.com timeout: 10 # デフォルト値のオーバーライド # Document end </syntaxhighlight> <br><br> == yaml-cppライブラリ == ==== yaml-cppライブラリとは ==== yaml-cppライブラリは、C++向けのYAMLパーサーおよびエミッタライブラリである。<br> <br> yaml-cppライブラリを使用することにより、C++でYAMLファイルの読み込み、操作、書き込みが可能になる。<br> また、設定ファイルの処理、データのシリアライズ / デシリアライズ、構造化データの操作等に広く使用されている。<br> <br> yaml-cppライブラリの特徴を以下に示す。<br> * C++ 11以降をサポート *: モダンなC++の機能を活用している。 * ヘッダオンリーライブラリ *: 使用する場合は、ヘッダファイルをインクルードするだけで済む。 * YAML 1.2仕様のサポート *: 最新のYAML仕様に準拠している。 * 例外ベースのエラー処理 *: エラーが発生した場合は、適切な例外をスローする。 * STLとの統合 *: STLコンテナとの相互運用性が高い。 * ストリーミングAPI *: 大きなファイルや継続的なデータストリームの処理に適している。 <br> ==== yaml-cppライブラリのライセンス ==== yaml-cppライブラリのライセンスは、MITライセンスに準拠している。<br> <br> ==== yaml-cppの主要なクラス ==== * YAML::Nodeクラス *: YAMLデータを表現する基本的なクラスである。 *: スカラー、シーケンス、マップ等、あらゆる種類のYAMLノードを表現できる。 * YAML::Exceptionクラス *: yaml-cppライブラリが投げる例外の基本クラスである。 *: パース時のエラーや型変換エラー等をキャッチできる。 * YAML::Emitterライブラリ *: YAMLデータを生成するためのクラスである。 *: プログラム上において、YAMLを構築する時に使用する。 * YAML::Parserクラス *: 低レベルのパーシング操作を行うためのクラスである。 *: 一般的には、<code>YAML::Load</code>クラスや<code>YAML::LoadFile</code>クラスを使用するため、直接使用することは少ない。 <br> <u>※注意</u><br> * 型安全性 *: <code>YAML::Node</code>クラスは、テンプレートベースの<code>.as<T></code>メソッドを提供するが、型が一致しない場合は例外がスローされる。 *: そのため、適切な型チェックを行うことが重要である。 * メモリ管理 *: <code>YAML::Node</code>クラスのオブジェクトは参照カウント方式で管理されているため、通常はメモリリークを心配する必要は無い。 * パフォーマンス *: 大規模なファイルを扱う場合、<code>YAML::LoadFile</code>クラスはファイル全体をメモリに読み込むため、メモリ使用量が増大する可能性がある。 *: この場合、ストリーミングAPIの使用を検討すること。 * エラー処理 *: yaml-cppライブラリは例外を使用してエラーを報告する。 *: そのため、適切な<code>try-catch</code>ブロックを使用して、エラーをハンドリングすることが重要である。 <br> ==== yaml-cppライブラリのインストール ==== ===== パッケージ管理システムからインストール ===== # RHEL sudo dnf install yaml-cpp yaml-cpp-devel # SUSE sudo zypper install yaml-cpp yaml-cpp-devel <br> ===== ソースコードからインストール ===== [https://github.com/jbeder/yaml-cpp yaml-cppライブラリのGithub]にアクセスして、ソースコードをダウンロードする。<br> ダウンロードしたファイルを解凍する。<br> tar xf yaml-cpp-<バージョン>.tar.gz cd yaml-cpp-<バージョン> <br> yaml-cppライブラリをビルドおよびインストールする。<br> mkdir build && cd build cmake -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_INSTALL_PREFIX=<yaml-cppライブラリのインストールディレクトリ> \ -DYAML_BUILD_SHARED_LIBS=ON \ .. make -j $(nproc) make install <br><br> == ライブラリの指定 == ==== Qtプロジェクトファイルを使用する場合 ==== <syntaxhighlight lang="make"> # Qtプロジェクトファイル # pkg-configを使用してyaml-cppライブラリを設定 CONFIG += link_pkgconfig PKGCONFIG += yaml-cpp # pkg-configを使用しない場合 LIBS += -lyaml-cpp </syntaxhighlight> <br> ==== CMakeLists.txtファイルを使用する場合 ==== <syntaxhighlight lang="cmake"> # CMakeLists.txtファイル # ...略 find_package(PkgConfig REQUIRED) # yaml-cppライブラリの指定 pkg_check_modules(YAML_CPP REQUIRED yaml-cpp) # インクルードディレクトリの指定 target_include_directories(${PROJECT_NAME} PRIVATE # ...略 ${YAML_CPP_INCLUDE_DIRS} ) # ...略 # ライブラリのリンク target_link_libraries(${PROJECT_NAME} PRIVATE # ...略 ${YAML_CPP_LIBRARIES} ) # コンパイルオプションの設定 target_compile_options(${PROJECT_NAME} PRIVATE # ...略 ${YAML_CPP_CFLAGS_OTHER} ) </syntaxhighlight> <br><br> == yaml-cppライブラリの使用例 == 以下の例では、yaml-cppライブラリの主な機能を使用している。<br> * YAMLファイルの読み込み (<code>YAML::LoadFile</code>クラスの使用) * スカラー値の取得 (<code>.as<T></code>メソッドの使用) * リストの処理 (範囲ベースのforループ) * ネストされたマップの処理 * 新しいYAMLノードの作成と操作 * YAMLデータの出力 (ストリーム演算子<code><<</code>の使用) * YAMLデータのファイルへの書き込み <br> <syntaxhighlight lang="c++"> // main.cppファイル #include <iostream> #include <yaml-cpp/yaml.h> int main() { try { // YAMLファイルの読み込み YAML::Node config = YAML::LoadFile("config.yaml"); // スカラー値の取得 std::string name = config["name"].as<std::string>(); int age = config["age"].as<int>(); std::cout << "Name: " << name << ", Age: " << age << std::endl; // リストの処理 std::cout << "Hobbies:" << std::endl; for (const auto &hobby : config["hobbies"]) { std::cout << "- " << hobby.as<std::string>() << std::endl; } // ネストされたマップの処理 if (config["address"]) { std::cout << "Address:" << std::endl; std::cout << " Street: " << config["address"]["street"].as<std::string>() << std::endl; std::cout << " City: " << config["address"]["city"].as<std::string>() << std::endl; } // 新しいYAMLノードの作成 YAML::Node newNode; newNode["key"] = "value"; newNode["list"].push_back(1); newNode["list"].push_back(2); newNode["list"].push_back(3); // YAMLの出力 std::cout << "\nNew YAML:\n" << newNode << std::endl; // YAMLファイルへの書き込み std::ofstream fout("output.yaml"); fout << newNode; fout.close(); } catch (const YAML::Exception& e) { std::cerr << "YAML error: " << e.what() << std::endl; return -1; } return 0; } </syntaxhighlight> <br> yaml-cppライブラリの詳細な使用方法は、[https://github.com/jbeder/yaml-cpp/wiki/Tutorial 公式ドキュメント]を参照すること。<br> <br> YAMLを出力するモデルは、<code>std::ostream</code>マニピュレータである。<br> <code>YAML::Emitter</code>クラスのオブジェクトは出力ストリームとして動作して、その出力は<code>c_str</code>メソッドで取得できる。<br> <code>YAML::Emitter</code>クラスの詳細な使用方法は、[https://github.com/jbeder/yaml-cpp/wiki/How-To-Emit-YAML 公式ドキュメント]を参照すること。<br> <br><br> == yaml-cppライブラリの応用例 == ==== 設定ファイルの管理 ==== 以下の例では、アプリケーションの設定をYAMLファイルで管理して、読み込み、更新、保存している。<br> <syntaxhighlight lang="c++"> #include <iostream> #include <fstream> #include <yaml-cpp/yaml.h> class ConfigManager { private: std::string m_filename; YAML::Node m_config; public: ConfigManager(const std::string &filename) : m_filename(filename) { load(); } void load() { try { m_config = YAML::LoadFile(m_filename); } catch (const YAML::Exception &e) { std::cerr << "Error loading config: " << e.what() << std::endl; } } void save() { try { std::ofstream fout(m_filename); fout << m_config; } catch (const YAML::Exception &e) { std::cerr << "Error saving config: " << e.what() << std::endl; } } template<typename T> T get(const std::string& key, const T &defaultValue) { try { return m_config[key].as<T>(); } catch (const YAML::Exception&) { return defaultValue; } } template<typename T> void set(const std::string &key, const T &value) { m_config[key] = value; } }; int main() { ConfigManager config("app_config.yaml"); // 設定の読み取り std::string username = config.get<std::string>("username", "default_user"); int port = config.get<int>("port", 8080); std::cout << "Username: " << username << std::endl; std::cout << "Port: " << port << std::endl; // 設定の更新 config.set("username", "new_user"); config.set("port", 9000); // 設定の保存 config.save(); return 0; } </syntaxhighlight> <br> ==== データ変換 ==== 以下の例では、YAML形式のデータを読み込み、新しい構造のYAMLデータとして出力している。<br> これは、例えば、ユーザデータを処理して統計情報を生成する場合に有用である。<br> <syntaxhighlight lang="c++"> #include <iostream> #include <vector> #include <algorithm> #include <yaml-cpp/yaml.h> struct UserData { std::string name; int age; std::vector<std::string> skills; }; YAML::Node processUserData(const YAML::Node& input) { std::vector<UserData> users; for (const auto& user : input["users"]) { UserData userData; userData.name = user["name"].as<std::string>(); userData.age = user["age"].as<int>(); userData.skills = user["skills"].as<std::vector<std::string>>(); users.push_back(userData); } // データ処理: 平均年齢とスキルの集計 int totalAge = 0; std::map<std::string, int> skillCount; for (const auto &user : users) { totalAge += user.age; for (const auto &skill : user.skills) { skillCount[skill]++; } } double averageAge = users.empty() ? 0 : static_cast<double>(totalAge) / users.size(); // 結果のYAMLノードを作成 YAML::Node output; output["total_users"] = users.size(); output["average_age"] = averageAge; YAML::Node skillStats; for (const auto &[skill, count] : skillCount) { skillStats[skill] = count; } output["skill_statistics"] = skillStats; return output; } int main() { try { YAML::Node input = YAML::LoadFile("user_data.yaml"); YAML::Node output = processUserData(input); std::cout << "Processed Data:\n" << output << std::endl; std::ofstream fout("user_statistics.yaml"); fout << output; } catch (const YAML::Exception &e) { std::cerr << "Error processing YAML: " << e.what() << std::endl; return -1; } return 0; } </syntaxhighlight> <br> ==== 階層的データ構造の操作 ==== 以下の例では、yaml-cppライブラリを使用して、複雑な階層的データ構造を操作している。<br> 組織構造を表すYAMLデータを読み込み、特定の条件に基づいて検索や更新を行う。<br> <syntaxhighlight lang="c++"> #include <iostream> #include <functional> #include <yaml-cpp/yaml.h> // 再帰的にYAMLノードを探索する関数 void traverseNode(YAML::Node& node, const std::function<void(YAML::Node&)>& callback) { if (node.IsMap()) { for (auto it = node.begin(); it != node.end(); ++it) { callback(it->second); traverseNode(it->second, callback); } } else if (node.IsSequence()) { for (auto& item : node) { callback(item); traverseNode(item, callback); } } } // 特定の条件に一致するノードを検索する関数 std::vector<YAML::Node> findNodes(YAML::Node& root, const std::function<bool(const YAML::Node&)>& predicate) { std::vector<YAML::Node> results; traverseNode(root, [&](YAML::Node &node) { if (predicate(node)) { results.push_back(node); } }); return results; } int main() { try { YAML::Node org = YAML::LoadFile("organization.yaml"); // 例: 全ての部門の予算を10%増加 traverseNode(org, [](YAML::Node& node) { if (node["budget"]) { double budget = node["budget"].as<double>(); node["budget"] = budget * 1.1; } }); // 例: 特定の役職を持つ従業員を検索 auto managers = findNodes(org, [](const YAML::Node& node) { return node["position"] && node["position"].as<std::string>() == "Manager"; }); std::cout << "Managers found: " << managers.size() << std::endl; for (const auto &manager : managers) { std::cout << "Name: " << manager["name"].as<std::string>() << std::endl; } // 更新されたデータを保存 std::ofstream fout("updated_organization.yaml"); fout << org; } catch (const YAML::Exception &e) { std::cerr << "Error processing YAML: " << e.what() << std::endl; return -1; } return 0; } </syntaxhighlight> <br><br> __FORCETOC__ [[カテゴリ:C++]]
C++の応用 - YAML
に戻る。
案内
メインページ
最近の更新
おまかせ表示
MediaWiki についてのヘルプ
ツール
リンク元
関連ページの更新状況
特別ページ
ページ情報
We ask for
Donations
Collapse