ClaudeにTOMLファイル読み込みについて聞いた
# GitHubからcloneする場合
$ git clone https://github.com/ToruNiina/toml11
# Ubuntu
$ apt install nlohmann-json3-dev libyaml-cpp-dev libtoml11-dev
# Redhat
$ dnf install https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm
$ dnf config-manager --enable codeready-builder-for-rhel-9-rhui-rpms
$ dnf install json-devel yaml-cpp-devel toml11-devel
// toml_config.h : テストパターン設定TOMLを読み込むクラス(toml11バックエンド)
// toml11: https://github.com/ToruNiina/toml11 (MITライセンス、C++11以上、ヘッダオンリー)
#ifndef TOML_CONFIG_H
#define TOML_CONFIG_H
#include <string>
#include <toml.hpp>
class TomlConfig {
public:
TomlConfig( void );
TomlConfig( const char *fname );
~TomlConfig( void );
bool load( const char *fname );
void release( void );
bool isLoaded( void ) const;
int getSectionNum( void ) const;
std::string getSectionName( int idx ) const;
bool hasSection( const char *section ) const;
bool hasKey( const char *section, const char *key ) const;
int getKeyNum( const char *section ) const;
std::string getKeyName( const char *section, int idx ) const;
int getInt( const char *section, const char *key, int defval ) const;
std::string getStr( const char *section, const char *key, const char *defval ) const;
private:
// ordered_type_config: セクションとキーのファイル記載順を保持する
typedef toml::basic_value<toml::ordered_type_config> Value;
bool loaded_;
Value root_;
const Value *findSec( const char *section ) const;
const Value *findVal( const char *section, const char *key ) const;
};
#endif
// toml_config.cpp
#include <cstdio>
#include "toml_config.h"
TomlConfig::TomlConfig( void )
{
loaded_ = false;
}
TomlConfig::TomlConfig( const char *fname )
{
loaded_ = false;
load(fname);
}
TomlConfig::~TomlConfig( void )
{
release();
}
bool TomlConfig::load( const char *fname )
{
release();
try {
root_ = toml::parse<toml::ordered_type_config>(fname);
} catch( const std::exception &e ) {
// 構文エラー時はtoml11が行番号と位置指示付きのメッセージを生成する
fprintf(stderr, "TomlConfig::load: %s\n", e.what());
return false;
}
loaded_ = true;
return true;
}
void TomlConfig::release( void )
{
root_ = Value();
loaded_ = false;
}
bool TomlConfig::isLoaded( void ) const
{
return loaded_;
}
int TomlConfig::getSectionNum( void ) const
{
if( !loaded_||!root_.is_table() ) {
return 0;
}
const auto &tbl = root_.as_table();
int n = 0;
for( auto it=tbl.begin(); it!=tbl.end(); ++it ) {
if( it->second.is_table() ) {
n++;
}
}
return n;
}
std::string TomlConfig::getSectionName( int idx ) const
{
if( loaded_&&root_.is_table() ) {
const auto &tbl = root_.as_table();
int n = 0;
for( auto it=tbl.begin(); it!=tbl.end(); ++it ) {
if( it->second.is_table() ) {
if( n==idx ) {
return it->first;
}
n++;
}
}
}
fprintf(stderr, "TomlConfig::getSectionName: out of range idx=%d (num=%d)\n",
idx, getSectionNum());
return "";
}
bool TomlConfig::hasSection( const char *section ) const
{
return findSec(section)!=NULL;
}
bool TomlConfig::hasKey( const char *section, const char *key ) const
{
return findVal(section, key)!=NULL;
}
int TomlConfig::getKeyNum( const char *section ) const
{
const Value *sec = findSec(section);
if( sec==NULL ) {
return 0;
}
return (int)sec->as_table().size();
}
std::string TomlConfig::getKeyName( const char *section, int idx ) const
{
const Value *sec = findSec(section);
if( sec!=NULL ) {
const auto &tbl = sec->as_table();
int n = 0;
for( auto it=tbl.begin(); it!=tbl.end(); ++it ) {
if( n==idx ) {
return it->first;
}
n++;
}
}
fprintf(stderr, "TomlConfig::getKeyName: out of range [%s] idx=%d\n", section, idx);
return "";
}
int TomlConfig::getInt( const char *section, const char *key, int defval ) const
{
const Value *v = findVal(section, key);
if( v==NULL ) {
return defval;
}
if( v->is_integer() ) {
return (int)v->as_integer();
}
if( v->is_boolean() ) {
return v->as_boolean() ? 1 : 0;
}
fprintf(stderr, "TomlConfig::getInt: [%s] %s is not an integer, use default %d\n",
section, key, defval);
return defval;
}
std::string TomlConfig::getStr( const char *section, const char *key, const char *defval ) const
{
const Value *v = findVal(section, key);
if( v==NULL ) {
return defval;
}
if( v->is_string() ) {
return v->as_string();
}
if( v->is_integer() ) {
return std::to_string(v->as_integer());
}
if( v->is_floating() ) {
return std::to_string(v->as_floating());
}
if( v->is_boolean() ) {
return v->as_boolean() ? "true" : "false";
}
fprintf(stderr, "TomlConfig::getStr: [%s] %s is not a string, use default \"%s\"\n",
section, key, defval);
return defval;
}
const TomlConfig::Value *TomlConfig::findSec( const char *section ) const
{
if( !loaded_||!root_.is_table() ) {
return NULL;
}
const auto &tbl = root_.as_table();
for( auto it=tbl.begin(); it!=tbl.end(); ++it ) {
if( it->first==section&&it->second.is_table() ) {
return &it->second;
}
}
return NULL;
}
const TomlConfig::Value *TomlConfig::findVal( const char *section, const char *key ) const
{
const Value *sec = findSec(section);
if( sec==NULL ) {
return NULL;
}
const auto &tbl = sec->as_table();
for( auto it=tbl.begin(); it!=tbl.end(); ++it ) {
if( it->first==key ) {
return &it->second;
}
}
return NULL;
}
// toml_main.cpp : TomlConfigの使用例(xlsx2toml.py生成ファイルの読み出し)
#include <cstdio>
#include "toml_config.h"
int main( int argc, char *argv[] )
{
const char *fname = "hoge.toml";
if( argc>=2 ) {
fname = argv[1];
}
TomlConfig cfg(fname);
if( !cfg.isLoaded() ) {
return 1;
}
// 先頭セクション名=パターン名
std::string num0 = cfg.getSectionName(0);
int num1 = cfg.getInt(num0.c_str(), "NUMBER1", 0);
int num2 = cfg.getInt(num0.c_str(), "NUMBER2", 0);
printf("num0=%s NUMBER1=%d NUMBER2=%d\n", num0.c_str(), num1, num2);
for( int i=0; i<num2; i++ ) {
char sec[64];
snprintf(sec, sizeof(sec), "NO_%d", i);
if( !cfg.hasSection(sec) ) {
fprintf(stderr, "missing section [%s]\n", sec);
return 1;
}
printf("[%s] name=%s\n", sec, cfg.getStr(sec, "name", "(none)").c_str());
for( int k=0; k<cfg.getKeyNum(sec); k++ ) {
std::string key = cfg.getKeyName(sec, k);
if( key=="name" ) {
continue;
}
printf(" %-20s = %d\n", key.c_str(), cfg.getInt(sec, key.c_str(), 0));
}
}
return 0;
}
[hoge]
NUMBER1=0
NUMBER2=2
[NO_0]
name="hoge_0"
kokugo = 100
sansuu = 1
rika = 0
syakai = 1
eigo = 1
[NO_1]
name="hoge_1"
kokugo = 100
sansuu = 1
rika = 0
syakai = 1
eigo = 1
# コンパイル
$ g++ -std=c++11 -O2 -Wall -I toml11/include -o toml_test toml_main.cpp toml_config.cpp
Claudeにjsonファイル読み込みについて聞いてみた
# GitHubからcloneする場合
$ git clone https://github.com/nlohmann/json
# Ubuntu
$ sudo apt install nlohmann-json3-dev
# Redhat
$ dnf install https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm
$ dnf config-manager --enable codeready-builder-for-rhel-9-rhui-rpms
$ dnf install json-devel
// json_config.h : テストパターン設定JSONを読み込むクラス(nlohmann/jsonバックエンド)
// nlohmann/json: https://github.com/nlohmann/json (MITライセンス、C++11以上、ヘッダオンリー)
#ifndef JSON_CONFIG_H
#define JSON_CONFIG_H
#include <string>
#include <nlohmann/json.hpp>
class JsonConfig {
public:
JsonConfig( void );
JsonConfig( const char *fname );
~JsonConfig( void );
bool load( const char *fname );
void release( void );
bool isLoaded( void ) const;
int getSectionNum( void ) const;
std::string getSectionName( int idx ) const;
bool hasSection( const char *section ) const;
bool hasKey( const char *section, const char *key ) const;
int getKeyNum( const char *section ) const;
std::string getKeyName( const char *section, int idx ) const;
int getInt( const char *section, const char *key, int defval ) const;
std::string getStr( const char *section, const char *key, const char *defval ) const;
private:
// ordered_json: セクションとキーのファイル記載順を保持する(既定のjsonはキーを辞書順ソートするため不可)
typedef nlohmann::ordered_json Value;
bool loaded_;
Value root_;
const Value *findSec( const char *section ) const;
const Value *findVal( const char *section, const char *key ) const;
};
#endif
// json_config.cpp
#include <cstdio>
#include <fstream>
#include "json_config.h"
JsonConfig::JsonConfig( void )
{
loaded_ = false;
}
JsonConfig::JsonConfig( const char *fname )
{
loaded_ = false;
load(fname);
}
JsonConfig::~JsonConfig( void )
{
release();
}
bool JsonConfig::load( const char *fname )
{
release();
std::ifstream ifs(fname);
if( !ifs ) {
fprintf(stderr, "JsonConfig::load: cannot open %s\n", fname);
return false;
}
try {
// 第4引数true: //と/* */のコメントを無視(手編集ファイルへの配慮。標準JSONにコメントはない)
root_ = Value::parse(ifs, nullptr, true, true);
} catch( const std::exception &e ) {
// 構文エラー時はnlohmannが行/桁位置付きのメッセージを生成する
fprintf(stderr, "JsonConfig::load: %s\n", e.what());
return false;
}
if( !root_.is_object() ) {
fprintf(stderr, "JsonConfig::load: %s: top level is not an object\n", fname);
release();
return false;
}
loaded_ = true;
return true;
}
void JsonConfig::release( void )
{
root_ = Value();
loaded_ = false;
}
bool JsonConfig::isLoaded( void ) const
{
return loaded_;
}
int JsonConfig::getSectionNum( void ) const
{
if( !loaded_ ) {
return 0;
}
int n = 0;
for( auto it=root_.begin(); it!=root_.end(); ++it ) {
if( it.value().is_object() ) {
n++;
}
}
return n;
}
std::string JsonConfig::getSectionName( int idx ) const
{
if( loaded_ ) {
int n = 0;
for( auto it=root_.begin(); it!=root_.end(); ++it ) {
if( it.value().is_object() ) {
if( n==idx ) {
return it.key();
}
n++;
}
}
}
fprintf(stderr, "JsonConfig::getSectionName: out of range idx=%d (num=%d)\n",
idx, getSectionNum());
return "";
}
bool JsonConfig::hasSection( const char *section ) const
{
return findSec(section)!=NULL;
}
bool JsonConfig::hasKey( const char *section, const char *key ) const
{
return findVal(section, key)!=NULL;
}
int JsonConfig::getKeyNum( const char *section ) const
{
const Value *sec = findSec(section);
if( sec==NULL ) {
return 0;
}
return (int)sec->size();
}
std::string JsonConfig::getKeyName( const char *section, int idx ) const
{
const Value *sec = findSec(section);
if( sec!=NULL ) {
int n = 0;
for( auto it=sec->begin(); it!=sec->end(); ++it ) {
if( n==idx ) {
return it.key();
}
n++;
}
}
fprintf(stderr, "JsonConfig::getKeyName: out of range [%s] idx=%d\n", section, idx);
return "";
}
int JsonConfig::getInt( const char *section, const char *key, int defval ) const
{
const Value *v = findVal(section, key);
if( v==NULL ) {
return defval;
}
if( v->is_number_integer() ) {
return (int)v->get<long long>();
}
if( v->is_boolean() ) {
return v->get<bool>() ? 1 : 0;
}
fprintf(stderr, "JsonConfig::getInt: [%s] %s is not an integer, use default %d\n",
section, key, defval);
return defval;
}
std::string JsonConfig::getStr( const char *section, const char *key, const char *defval ) const
{
const Value *v = findVal(section, key);
if( v==NULL ) {
return defval;
}
if( v->is_string() ) {
return v->get<std::string>();
}
if( v->is_number_integer() ) {
return std::to_string(v->get<long long>());
}
if( v->is_number_float() ) {
return std::to_string(v->get<double>());
}
if( v->is_boolean() ) {
return v->get<bool>() ? "true" : "false";
}
fprintf(stderr, "JsonConfig::getStr: [%s] %s is not a string, use default \"%s\"\n",
section, key, defval);
return defval;
}
const JsonConfig::Value *JsonConfig::findSec( const char *section ) const
{
if( !loaded_ ) {
return NULL;
}
for( auto it=root_.begin(); it!=root_.end(); ++it ) {
if( it.key()==section&&it.value().is_object() ) {
return &it.value();
}
}
return NULL;
}
const JsonConfig::Value *JsonConfig::findVal( const char *section, const char *key ) const
{
const Value *sec = findSec(section);
if( sec==NULL ) {
return NULL;
}
for( auto it=sec->begin(); it!=sec->end(); ++it ) {
if( it.key()==key ) {
return &it.value();
}
}
return NULL;
}
// json_main.cpp : JsonConfigの使用例(xlsx2json.py生成ファイルの読み出し)
#include <cstdio>
#include "json_config.h"
int main( int argc, char *argv[] )
{
const char *fname = "hoge.json";
if( argc>=2 ) {
fname = argv[1];
}
JsonConfig cfg(fname);
if( !cfg.isLoaded() ) {
return 1;
}
// 先頭セクション名=パターン名
std::string num0 = cfg.getSectionName(0);
int num1 = cfg.getInt(num0.c_str(), "NUMBER1", 0);
int num2 = cfg.getInt(num0.c_str(), "NUMBER2", 0);
printf("num0=%s NUMBER1=%d NUMBER2=%d\n", num0.c_str(), num1, num2);
for( int i=0; i<num2; i++ ) {
char sec[64];
snprintf(sec, sizeof(sec), "NO_%d", i);
if( !cfg.hasSection(sec) ) {
fprintf(stderr, "missing section [%s]\n", sec);
return 1;
}
printf("[%s] name=%s\n", sec, cfg.getStr(sec, "name", "(none)").c_str());
for( int k=0; k<cfg.getKeyNum(sec); k++ ) {
std::string key = cfg.getKeyName(sec, k);
if( key=="name" ) {
continue;
}
printf(" %-20s = %d\n", key.c_str(), cfg.getInt(sec, key.c_str(), 0));
}
}
return 0;
}
{
"hoge": {
"NUMBER1": 0,
"NUMBER2": 2
},
"NO_0": {
"name": "hoge_0",
"kokugo": 100,
"sansuu": 1,
"rika": 0,
"syakai": 1,
"eigo": 1
},
"NO_1": {
"name": "hoge_1",
"kokugo": 100,
"sansuu": 1,
"rika": 0,
"syakai": 1,
"eigo": 1
}
}
# コンパイル
g++ -std=c++11 -O2 -Wall -I json/single_include -o json_test json_main.cpp json_config.cpp
Claudeにyamlファイル読み込みについて聞いてみた
# Ubuntuの場合
$ sudo apt install libyaml-cpp-dev
# Redhatの場合
$ sudo dnf install yaml-cpp-devel
// yaml_config.h : テストパターン設定YAMLを読み込むクラス(yaml-cppバックエンド)
// yaml-cpp: https://github.com/jbeder/yaml-cpp (MIT/X11ライセンス、C++11以上、要リンク -lyaml-cpp)
#ifndef YAML_CONFIG_H
#define YAML_CONFIG_H
#include <string>
#include <yaml-cpp/yaml.h>
class YamlConfig {
public:
YamlConfig( void );
YamlConfig( const char *fname );
~YamlConfig( void );
bool load( const char *fname );
void release( void );
bool isLoaded( void ) const;
int getSectionNum( void ) const;
std::string getSectionName( int idx ) const;
bool hasSection( const char *section ) const;
bool hasKey( const char *section, const char *key ) const;
int getKeyNum( const char *section ) const;
std::string getKeyName( const char *section, int idx ) const;
int getInt( const char *section, const char *key, int defval ) const;
std::string getStr( const char *section, const char *key, const char *defval ) const;
private:
bool loaded_;
YAML::Node root_; // yaml-cppのマップ走査は記載順を保持する
YAML::Node findSec( const char *section ) const;
YAML::Node findVal( const char *section, const char *key ) const;
};
#endif
// yaml_config.cpp
#include <cstdio>
#include "yaml_config.h"
YamlConfig::YamlConfig( void )
{
loaded_ = false;
}
YamlConfig::YamlConfig( const char *fname )
{
loaded_ = false;
load(fname);
}
YamlConfig::~YamlConfig( void )
{
release();
}
bool YamlConfig::load( const char *fname )
{
release();
try {
root_ = YAML::LoadFile(fname);
} catch( const std::exception &e ) {
// 構文エラー時はyaml-cppが行/桁位置付きのメッセージを生成する
fprintf(stderr, "YamlConfig::load: %s: %s\n", fname, e.what());
return false;
}
if( !root_.IsMap() ) {
fprintf(stderr, "YamlConfig::load: %s: top level is not a map\n", fname);
release();
return false;
}
loaded_ = true;
return true;
}
void YamlConfig::release( void )
{
root_ = YAML::Node(YAML::NodeType::Undefined);
loaded_ = false;
}
bool YamlConfig::isLoaded( void ) const
{
return loaded_;
}
int YamlConfig::getSectionNum( void ) const
{
if( !loaded_ ) {
return 0;
}
int n = 0;
for( YAML::const_iterator it=root_.begin(); it!=root_.end(); ++it ) {
if( it->second.IsMap() ) {
n++;
}
}
return n;
}
std::string YamlConfig::getSectionName( int idx ) const
{
if( loaded_ ) {
int n = 0;
for( YAML::const_iterator it=root_.begin(); it!=root_.end(); ++it ) {
if( it->second.IsMap() ) {
if( n==idx ) {
return it->first.as<std::string>();
}
n++;
}
}
}
fprintf(stderr, "YamlConfig::getSectionName: out of range idx=%d (num=%d)\n",
idx, getSectionNum());
return "";
}
bool YamlConfig::hasSection( const char *section ) const
{
return findSec(section).IsDefined();
}
bool YamlConfig::hasKey( const char *section, const char *key ) const
{
return findVal(section, key).IsDefined();
}
int YamlConfig::getKeyNum( const char *section ) const
{
YAML::Node sec = findSec(section);
if( !sec.IsDefined() ) {
return 0;
}
return (int)sec.size();
}
std::string YamlConfig::getKeyName( const char *section, int idx ) const
{
YAML::Node sec = findSec(section);
if( sec.IsDefined() ) {
int n = 0;
for( YAML::const_iterator it=sec.begin(); it!=sec.end(); ++it ) {
if( n==idx ) {
return it->first.as<std::string>();
}
n++;
}
}
fprintf(stderr, "YamlConfig::getKeyName: out of range [%s] idx=%d\n", section, idx);
return "";
}
int YamlConfig::getInt( const char *section, const char *key, int defval ) const
{
YAML::Node v = findVal(section, key);
if( !v.IsDefined() ) {
return defval;
}
try {
return v.as<int>();
} catch( const std::exception & ) {
}
try {
return v.as<bool>() ? 1 : 0;
} catch( const std::exception & ) {
}
fprintf(stderr, "YamlConfig::getInt: [%s] %s is not an integer, use default %d\n",
section, key, defval);
return defval;
}
std::string YamlConfig::getStr( const char *section, const char *key, const char *defval ) const
{
YAML::Node v = findVal(section, key);
if( !v.IsDefined() ) {
return defval;
}
if( v.IsScalar() ) {
return v.as<std::string>();
}
fprintf(stderr, "YamlConfig::getStr: [%s] %s is not a scalar, use default \"%s\"\n",
section, key, defval);
return defval;
}
YAML::Node YamlConfig::findSec( const char *section ) const
{
if( loaded_ ) {
for( YAML::const_iterator it=root_.begin(); it!=root_.end(); ++it ) {
if( it->first.as<std::string>()==section&&it->second.IsMap() ) {
return it->second;
}
}
}
return YAML::Node(YAML::NodeType::Undefined);
}
YAML::Node YamlConfig::findVal( const char *section, const char *key ) const
{
YAML::Node sec = findSec(section);
if( sec.IsDefined() ) {
for( YAML::const_iterator it=sec.begin(); it!=sec.end(); ++it ) {
if( it->first.as<std::string>()==key ) {
return it->second;
}
}
}
return YAML::Node(YAML::NodeType::Undefined);
}
// yaml_main.cpp : YamlConfigの使用例(xlsx2yaml.py生成ファイルの読み出し)
#include <cstdio>
#include "yaml_config.h"
int main( int argc, char *argv[] )
{
const char *fname = "hoge.yaml";
if( argc>=2 ) {
fname = argv[1];
}
YamlConfig cfg(fname);
if( !cfg.isLoaded() ) {
return 1;
}
// 先頭セクション名=パターン名
std::string num0 = cfg.getSectionName(0);
int num1 = cfg.getInt(num0.c_str(), "NUMBER1", 0);
int num2 = cfg.getInt(num0.c_str(), "NUMBER2", 0);
printf("num0=%s NUMBER1=%d NUMBER2=%d\n", num0.c_str(), num1, num2);
for( int i=0; i<num2; i++ ) {
char sec[64];
snprintf(sec, sizeof(sec), "NO_%d", i);
if( !cfg.hasSection(sec) ) {
fprintf(stderr, "missing section [%s]\n", sec);
return 1;
}
printf("[%s] name=%s\n", sec, cfg.getStr(sec, "name", "(none)").c_str());
for( int k=0; k<cfg.getKeyNum(sec); k++ ) {
std::string key = cfg.getKeyName(sec, k);
if( key=="name" ) {
continue;
}
printf(" %-20s = %d\n", key.c_str(), cfg.getInt(sec, key.c_str(), 0));
}
}
return 0;
}
hoge:
NUMBER1: 0
NUMBER2: 2
NO_0:
name: hoge_0.bin
kokugo: 100
sansuu: 1
rika: 0
syakai: 1
eigo: 1
NO_1:
name: hoge_0.bin
kokugo: 100
sansuu: 1
rika: 0
syakai: 1
eigo: 1
# コンパイル
g++ -std=c++11 -O2 -Wall -I json/single_include -o json_test json_main.cpp json_config.cpp