Aidez à améliorer ce code d'analyse INI
Question
C’est quelque chose de simple que j’ai imaginé pour cette question . Je ne suis pas entièrement satisfait de cela et je l'ai vu comme une chance d'améliorer mon utilisation de la STL et de la programmation par flux.
std::wifstream file(L"\\Windows\\myini.ini");
if (file)
{
bool section=false;
while (!file.eof())
{
std::wstring line;
std::getline(file, line);
if (line.empty()) continue;
switch (line[0])
{
// new header
case L'[':
{
std::wstring header;
size_t pos=line.find(L']');
if (pos!=std::wstring::npos)
{
header=line.substr(1, pos);
if (header==L"Section")
section=true;
else
section=false;
}
}
break;
// comments
case ';':
case ' ':
case '#':
break;
// var=value
default:
{
if (!section) continue;
// what if the name = value does not have white space?
// what if the value is enclosed in quotes?
std::wstring name, dummy, value;
lineStm >> name >> dummy;
ws(lineStm);
WCHAR _value[256];
lineStm.getline(_value, ELEMENTS(_value));
value=_value;
}
}
}
}
Comment amélioreriez-vous cela? S'il vous plaît, ne recommandez pas d'autres bibliothèques. Je veux juste une méthode simple pour analyser certaines chaînes de configuration à partir d'un fichier INI.
La solution
// Que se passe-t-il si la valeur nom = n'a pas d'espace blanc?
// que se passe-t-il si la valeur est entre guillemets?
J'utiliserais boost :: regex pour apparier chaque type d'élément, par exemple:
boost::smatch matches;
boost::regex name_value("(\S+)\s*=\s*(\S+)");
if(boost::regex_match(line, matches, name_value))
{
name = matches[1];
value = matches[2];
}
les expressions régulières ont peut-être besoin d'être peaufinées.
Je voudrais aussi remplacer de stream.getline par std :: getline, en éliminant le tableau de caractères statiques.
Autres conseils
Ceci:
for (size_t i=1; i<line.length(); i++)
{
if (line[i]!=L']')
header.push_back(line[i]);
else
break;
}
devrait être simplifié par un appel à wstrchr, wcschr, WSTRCHR ou autre chose, selon la plate-forme sur laquelle vous vous trouvez.
// comment obtenir une ligne dans une chaîne en une fois?
Utilisez la fonction getline (non membre) de l'en-tête de chaîne standard.