Créer un fichier de configuration simple et un parsingur en C ++

J’essaie de créer un fichier de configuration simple qui ressemble à ceci

url = http://mysite.com file = main.exe true = 0 

Lorsque le programme s’exécute, j’aimerais qu’il charge les parameters de configuration dans les variables de programmes répertoriées ci-dessous.

 ssortingng url, file; bool true_false; 

J’ai fait quelques recherches et ce lien a semblé aider (post de nucléon) mais je n’arrive pas à le faire fonctionner et c’est trop compliqué à comprendre de ma part. Y a-t-il un moyen simple de le faire? Je peux charger le fichier en utilisant ifstream mais c’est aussi loin que je peux le faire moi-même. Merci!

En général, il est plus facile d’parsingr ces fichiers de configuration typiques en deux étapes: lisez d’abord les lignes, puis parsingz-les une par une.
En C ++, les lignes peuvent être lues à partir d’un stream en utilisant std::getline() . Bien que par défaut il lira jusqu’au prochain '\n' (qu’il consumra, mais ne retournera pas), vous pouvez lui transmettre un autre délimiteur, ce qui en fait un bon candidat pour la lecture de certains caractères , comme = dans votre exemple.

Pour simplifier, les éléments suivants supposent que les = ne sont pas entourés d’espaces. Si vous voulez autoriser les espaces blancs à ces positions, vous devrez placer stratégiquement is >> std::ws avant de lire la valeur et supprimer les espaces blancs des clés. Cependant, la faible flexibilité de la syntaxe ne vaut pas la peine pour un lecteur de fichier de configuration.

 const char config[] = "url=http://example.com\n" "file=main.exe\n" "true=0"; std::issortingngstream is_file(config); std::ssortingng line; while( std::getline(is_file, line) ) { std::issortingngstream is_line(line); std::ssortingng key; if( std::getline(is_line, key, '=') ) { std::ssortingng value; if( std::getline(is_line, value) ) store_line(key, value); } } 

(L’ajout de la gestion des erreurs rest un exercice pour le lecteur.)

Comme d’autres l’ont souligné, il serait probablement moins utile d’utiliser une bibliothèque d’parsingurs de fichiers de configuration existante que de réinventer la roue.

Par exemple, si vous décidez d’utiliser la bibliothèque Config4Cpp (que je gère), la syntaxe de votre fichier de configuration sera légèrement différente (placez des guillemets doubles autour des valeurs et terminez les instructions d’affectation par un point-virgule).

 # File: someFile.cfg url = "http://mysite.com"; file = "main.exe"; true_false = "true"; 

Le programme suivant parsing le fichier de configuration ci-dessus, copie les valeurs souhaitées dans des variables et les imprime:

 #include  #include  using namespace config4cpp; using namespace std; int main(int argc, char ** argv) { Configuration * cfg = Configuration::create(); const char * scope = ""; const char * configFile = "someFile.cfg"; const char * url; const char * file; bool true_false; try { cfg->parse(configFile); url = cfg->lookupSsortingng(scope, "url"); file = cfg->lookupSsortingng(scope, "file"); true_false = cfg->lookupBoolean(scope, "true_false"); } catch(const ConfigurationException & ex) { cerr << ex.c_str() << endl; cfg->destroy(); return 1; } cout << "url=" << url << "; file=" << file << "; true_false=" << true_false << endl; cfg->destroy(); return 0; } 

Le site Web Config4Cpp fournit une documentation complète, mais la lecture des chapitres 2 et 3 du “Guide de démarrage” devrait être plus que suffisante pour répondre à vos besoins.

Une approche naïve pourrait ressembler à ceci:

 #include  #include  #include  #include  std::map options; // global? void parse(std::istream & cfgfile) { for (std::ssortingng line; std::getline(cfgfile, line); ) { std::issortingngstream iss(line); std::ssortingng id, eq, val; bool error = false; if (!(iss >> id)) { error = true; } else if (id[0] == '#') { continue; } else if (!(iss >> eq >> val >> std::ws) || eq != "=" || iss.get() != EOF) { error = true; } if (error) { // do something appropriate: throw, skip, warn, etc. } else { options[id] = val; } } } 

Maintenant, vous pouvez accéder à chaque valeur d’option à partir de la carte des options globales options n’importe où dans votre programme. Si vous voulez la castability, vous pouvez faire du type mappé un boost::variant .

libconfig est très simple et, mieux encore, il utilise une notation pseudo-json pour une meilleure lisibilité.

Facile à installer sur Ubuntu: sudo apt-get install libconfig++8-dev

et lien: -lconfig++

Pourquoi ne pas essayer quelque chose de simple et lisible par l’homme, comme JSON (ou XML)?

Il existe de nombreuses implémentations open-source prédéfinies de JSON (ou XML) pour C ++. J’en utiliserais une.

Et si vous voulez quelque chose de plus “binary” – essayez BJSON ou BSON 🙂

Que diriez-vous de formater votre configuration en tant que JSON et d’utiliser une bibliothèque comme jsoncpp ?

par exemple

 {"url": "http://mysite dot com", "file": "main.exe", "true": 0} 

Vous pouvez ensuite le lire dans des variables nommées, ou même le stocker dans un fichier std :: map, etc.

J’ai récemment effectué des recherches dans les bibliothèques d’parsing de configuration pour mon projet et j’ai trouvé ces bibliothèques:

Voici un travail simple pour les espaces blancs entre le signe ‘=’ et les données, dans le fichier de configuration. Affectez au stream entrant depuis l’emplacement après le signe ‘=’ et, en le lisant, tout espace blanc en tête est ignoré.

Remarque: lorsque vous utilisez un issortingngstream dans une boucle, assurez-vous d’appeler clear () avant de lui affecter une nouvelle chaîne.

 //config.txt //Input name = image1.png //Num. of rows = 100 //Num. of cols = 150 std::ssortingng ipName; int nR, nC; std::ifstream fin("config.txt"); std::ssortingng line; std::issortingngstream sin; while (std::getline(fin, line)) { sin.str(line.substr(line.find("=")+1)); if (line.find("Input name") != std::ssortingng::npos) { std::cout<<"Input name "<> ipName; } else if (line.find("Num. of rows") != std::ssortingng::npos) { sin >> nR; } else if (line.find("Num. of cols") != std::ssortingng::npos) { sin >> nC; } sin.clear(); }