boostでiniファイルを読み込んでmapに詰め込む
いつも地味に面倒なiniからの読み込みを簡単にするためにboost::property_treeでiniファイルを読み込んでmap<string,string>に詰め込むサンプル。
読み込むiniファイル(sample.ini)
[sectionA] key1 = val1 [section B] spaced key = spaced value [section C] # comment key1 = 1 # duped name key2 = あ ; japanee # comment ; comment
ソース(おためし)
まずは試しに表示するソースコード。普通にget_value()すると'='以降すべて取得できてしまうので、特定の文字以降をコメントとして扱いたい場合はsplit()してtrim()してあげる必要があるみたい。
#include <iostream> #include <string> #include <vector> #include <boost/property_tree/ptree.hpp> #include <boost/property_tree/ini_parser.hpp> #include <boost/algorithm/string.hpp> void printIni2(const char* filepath) { using boost::property_tree::ptree; ptree pt; read_ini( filepath, pt, std::locale("japanese") ); std::vector<std::string> valStrList; for (auto& section : pt) { std::cout << '[' << section.first << "]" << std::endl; for (auto& key : section.second) { std::string valStr = key.second.get_value<std::string>(); boost::split(valStrList, valStr, boost::is_any_of("#;")); std::cout << key.first << "=" << boost::algorithm::trim_copy(valStrList.at(0)) << std::endl; } } } void printIni(const char* filepath) { using boost::property_tree::ptree; ptree pt; read_ini( filepath, pt, std::locale("japanese") ); for (auto& section : pt) { // print part of "[section name]" std::cout << '[' << section.first << "]" << std::endl; // print part of "key = value" for (auto& key : section.second) { std::cout << key.first << "=" << key.second.get_value<std::string>() << std::endl; } } } int main(int argc, char* argv[]) { printIni("sample.ini"); std::cout << "--------------------------------" << std::endl; printIni2("sample.ini"); return 0; }
結果
[sectionA] key1=val1 [section B] spaced key=spaced value [section C] key1=1 # duped name key2=あ ; japanee -------------------------------- [sectionA] key1=val1 [section B] spaced key=spaced value [section C] key1=1 key2=あ
ソース(本題)
本題のソースコード。
#include <iostream> #include <string> #include <vector> #include <map> #include <boost/property_tree/ptree.hpp> #include <boost/property_tree/ini_parser.hpp> #include <boost/algorithm/string.hpp> #include <boost/lexical_cast.hpp> void ini2map(const char* filepath, std::map<std::string, std::string>& iniMap) { using boost::property_tree::ptree; ptree pt; read_ini( filepath, pt, std::locale("japanese") ); std::vector<std::string> valStrList; for (auto& section : pt) { std::string sectionName = section.first; for (auto& key : section.second) { std::string valStr = key.second.get_value<std::string>(); boost::split(valStrList, valStr, boost::is_any_of("#;")); std::string keyName = key.first; std::string val = boost::algorithm::trim_copy(valStrList.at(0)); std::cout << keyName << "=" << val << std::endl; iniMap[sectionName+"."+keyName] = val; } } } int main(int argc, char* argv[]) { std::map<std::string, std::string> iniMap; ini2map("sample.ini", iniMap); std::cout << iniMap.size() << std::endl; // print for( auto kvp : iniMap ) { std::cout << kvp.first << "=" << kvp.second << std::endl; } // get value as int std::cout << boost::lexical_cast<int>(iniMap.at("section C.key1")) << std::endl; // get value (failure) try { std::string valStr = iniMap.at(" undefined key "); } catch(std::exception& e) { std::cout << e.what() << std::endl; } return 0; }
結果
key1=val1 spaced key=spaced value key1=1 key2=あ 4 section B.spaced key=spaced value section C.key1=1 section C.key2=あ sectionA.key1=val1 1 map::at
ソース(おまけ)
ぶっちゃけ以下のようなコードで取得できるだろうけど、プロパティツリーを意識しないようにしたかった。あとこの場合は行内コメントできない。
ptree pt; read_ini("ini file", pt); string strValue = pt.get<string>("[section].item"); int intValue = pt.get<int>("[section].item");
メモ:
- forループの部分がこれで回るのはptreeが「map< string, map
> >」みたいな入れ子構造になっているかららしい。 - セクションがない項目は1階層目に入るので今回のコードだとうまく扱えない。
- せっかくなのでread_iniのロケールにjapanese指定してみたけど、実は指定しなくてもSJISのファイル読めた。逆にjapanese指定してもutf-8のファイル読めた。この辺はよくわからない。
- 環境:c++11 + boost 1.53
参考: