2008-09-28 8 views
2

C'est quelque chose de simple je suis venu avec this question. Je ne suis pas entièrement satisfait et je l'ai vu comme une chance d'aider à améliorer mon utilisation de la programmation STL et basée sur les flux.Aider à améliorer ce code d'analyse INI

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 voulez-vous améliorer cela? S'il vous plaît ne recommande pas de bibliothèques alternatives - Je veux juste une méthode simple pour analyser certaines chaînes de configuration à partir d'un fichier INI.

Répondre

3

// et si le nom = valeur n'a pas d'espace blanc?
// Et si la valeur est entre guillemets?

J'utiliser boost :: regex pour correspondre à tous les différents types d'éléments, quelque chose comme:

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 pourraient avoir besoin de quelques ajustements.

Je remplacerais aussi de stream.getline par std :: getline, en supprimant le tableau char statique.

1

Ce:

for (size_t i=1; i<line.length(); i++) 
     { 
      if (line[i]!=L']') 
      header.push_back(line[i]); 
      else 
      break; 
     } 

devrait être simplifiée par un appel à wstrchr, wcschr, WSTRCHR, ou autre chose, selon ce que la plate-forme que vous êtes.

+0

Je ne suis pas vraiment satisfait de cela - cela nécessiterait deux passages dans la chaîne pour extraire le nom de l'en-tête. La méthode actuelle est un seul passage. –

+0

Bien que l'implémentation actuelle n'ait qu'un seul passage à travers la chaîne, elle a N appels à push_back. Je ne pense pas que le compromis soit susceptible d'être bénéfique! –

+0

Oui, je pense que vous avez raison –

1

// comment obtenir une ligne dans une chaîne en une fois?

Utilisez la fonction (non membre) getline de l'en-tête de chaîne standard.