View Full Version : [C++] Lettura file testo con tag
Ciao ragazzi, volevo chiedervi quale è il modo più intelligente per leggere un file di questo tipo:
[name]
nome = pippo
[surname]
cognome = topolino
[tag_1]
val_1 = a;
[tag_2]
val_2 = b;
..
..
[tag_n]
val_n = n
i valori dentro tag sono casuali. E' solo per dare un'idea. E non tutti hanno un numero progressivo nel nome. Sto smanettando un pò con le string, ma e' piuttosto spartano.
I tag potrebbero anche non essere in questo ordine ( almeno quelli senza numero progressivo)
Vincenzo1968
22-09-2008, 20:15
Ciao ragazzi, volevo chiedervi quale è il modo più intelligente per leggere un file di questo tipo:
[name]
nome = pippo
[surname]
cognome = topolino
[tag_1]
val_1 = a;
[tag_2]
val_2 = b;
..
..
[tag_n]
val_n = n
i valori dentro tag sono casuali. E' solo per dare un'idea. E non tutti hanno un numero progressivo nel nome. Sto smanettando un pò con le string, ma e' piuttosto spartano.
I tag potrebbero anche non essere in questo ordine ( almeno quelli senza numero progressivo)
Dipende da cosa intendi per 'modo più intelligente'. Se ti riferisci alle prestazioni la cosa si può agevolmente risolvere con un automa a stati finiti.
Il prezzo da pagare è nella maggiore quantità, rispetto ad altre soluzioni, di linee di codice da scrivere. Se questo prezzo sei disposto a pagarlo, ti posso fare un esempio.
Ciao :)
DanieleC88
22-09-2008, 21:07
Be' se le tag iniziano e finiscono con [] e non sono precedute da spazi direi:
leggi la riga controlla che inizi per [ se è vero, leggi il nome della nuova tag finché non incontri ] e poi ricomincia a leggere da una nuova riga se non è vero, allora elimina gli spazi iniziali e finali in eccedenza controlla la stringa: se è vuota, torna all'inizio leggendo la prossima riga in caso contrario leggi la riga col valore
e ovviamente mi occuperei di gestire correttamente il parsing della riga (salto i punti di quest'ultimo passo, che sono comunque simili). Giusto un'idea. ;)
Si, basta usare l'operatore >> dal file, che ottiene una parola escludendo spazi e caratteri whitespace in generale... quindi controllare se il primo carattere della stringa ottenuta è [, e se l'ultimo è ].
Se è vero interpreti il testo interno come comando, e le stringhe successive come parametri, o roba del genere :asd:
Poi, quando incontri una nuova tag resetti i parametri e rifai da capo.
Cmq che ci devi fare con le istruzioni dopo le tags? e come sono strutturate?
Si, basta usare l'operatore >> dal file, che ottiene una parola escludendo spazi e caratteri whitespace in generale... quindi controllare se il primo carattere della stringa ottenuta è [, e se l'ultimo è ].
Se è vero interpreti il testo interno come comando, e le stringhe successive come parametri, o roba del genere :asd:
Poi, quando incontri una nuova tag resetti i parametri e rifai da capo.
Cmq che ci devi fare con le istruzioni dopo le tags? e come sono strutturate?
Con quei tag devo inizializzare dei valori all'interno di alcune classi. Solo che qualche tag potrebbe non essere presente. Ad esempio, se includo tutti i tag possibili da leggere in un blocco try/catch, se un tag non è presente, quindi si entra nel blocco catch, è possibile rientrare nel try, ma partendo dalla riga dopo che ha generato il catch? Al momento mi sfugge come si faccia :fagiano:
tomminno
23-09-2008, 12:34
Potresti usare le regex.
Potresti usare automi a stati finiti, implementando la lettura manuale riga per riga.
Ma perchè complicarsi la vita e non usare l'XML? Trovi parser già pronti per tutte le esigenze.
Se proprio vuoi scriverti un parser a mano devi considerare che potresti trovare anche documenti non validi, esempio valori con i caratteri "riservati" "[" o "]"
Potresti usare le regex.
Potresti usare automi a stati finiti, implementando la lettura manuale riga per riga.
Ma perchè complicarsi la vita e non usare l'XML? Trovi parser già pronti per tutte le esigenze.
Se proprio vuoi scriverti un parser a mano devi considerare che potresti trovare anche documenti non validi, esempio valori con i caratteri "riservati" "[" o "]"
Anche io volevo usare XML, ma devo usare questo formato e non lo posso cambiare :stordita:
Vincenzo1968
23-09-2008, 13:07
Potresti usare le regex.
Potresti usare automi a stati finiti, implementando la lettura manuale riga per riga.
Ma perchè complicarsi la vita e non usare l'XML? Trovi parser già pronti per tutte le esigenze.
Se proprio vuoi scriverti un parser a mano devi considerare che potresti trovare anche documenti non validi, esempio valori con i caratteri "riservati" "[" o "]"
Quelli che hai descritto sono problemi agevolmente gestibili con un automa a stati. Anzi, è proprio per risolvere questo tipo di problemi che sono stati ideati gli automi.
Secondo me è già un complicarsi la vita usare usare un file in formato XML dovendo stare attenti a rispettare la corretta struttura dei nodi quando se ne crea uno.
In fondo si tratta di effettuare il parsing di un semplice file, non dobbiamo certo implementare un compilatore.
P.S.
E se fosse necessario tenere conto delle prestazioni, implementare a mano la propria libreria per regex non sarebbe una cattiva idea: http://swtch.com/~rsc/regexp/regexp1.html ;)
Con quei tag devo inizializzare dei valori all'interno di alcune classi. Solo che qualche tag potrebbe non essere presente. Ad esempio, se includo tutti i tag possibili da leggere in un blocco try/catch, se un tag non è presente, quindi si entra nel blocco catch, è possibile rientrare nel try, ma partendo dalla riga dopo che ha generato il catch? Al momento mi sfugge come si faccia :fagiano:
Mi pare eccessivo usare il try catch, in realtà basta benissimo una sequenza di if else:
string s;
file >> s;
if( s[0] == '[' && s[s.length()] == ']')
{
if( s == "[name]") {...}
else if( s == "[surname]" ) {...}
else if( s == ... ) {...}
}
E così via... in questo modo poi le tags possono essere messe in qualsiasi maniera, o mancare del tutto.
Semplicemente, quando vengono lette il codice corrispondente è attivato.
Ciao ragazzi, volevo chiedervi quale è il modo più intelligente per leggere un file di questo tipo:
[name]
nome = pippo
[surname]
cognome = topolino
[tag_1]
val_1 = a;
[tag_2]
val_2 = b;
..
..
[tag_n]
val_n = n
i valori dentro tag sono casuali. E' solo per dare un'idea. E non tutti hanno un numero progressivo nel nome. Sto smanettando un pò con le string, ma e' piuttosto spartano.
I tag potrebbero anche non essere in questo ordine ( almeno quelli senza numero progressivo)
Alternative:
1 - Fai a mano, come spiegato sopra. Se non hai bisogno di un gran controllo sugli errori puo' essere una alternativa abbastsanza rapido.
2 - Regex, usando una delle varie librerie presenti, ad esempio quella in boost (http://www.boost.org/doc/libs/1_36_0/libs/regex/doc/html/index.html)
Ti viene abbastanza facile, visto che la regex per l'inizio sezione e' "\[(.*?)\]", mentre quella delle keywords puoi partire da qualcosa tipo "(.*?)=(.*?)" (per poi fare eventualmente tu conversioni e trim): lavori una linea alla volta, se la linea matcha la prima regex cominci una nuova sezione, se matcha la seconda aggiorni la map (o quel che usi) e se entrambe falliscono errore.
3 - Usi un generatore di parser piu' complesso (tipo http://spirit.sourceforge.net) ma non penso ne valga la pena.
Il modo piu' semplice e' probabilmente usare uno tra il metodo 1 e 2, leggere riga per riga, se e' del primo tipo inizi la nuova sezione, se del secondo metti in mappa il valore, altrimenti segnali l'errore.
Anche io volevo usare XML, ma devo usare questo formato e non lo posso cambiare :stordita:
Parafrasando Jamie Zawinski,
Some people, when confronted with a configuration file, think “I know, I’ll use XML.” Now they have two problems.
:D
Vincenzo1968
23-09-2008, 23:13
File tags.txt:
[name]
nome = pippo
[surname]
cognome = topolino
[tag_1]
val_1 = a
[tag_2]
val_2 = b
[tag_n]
val_n = n
File tags2.txt:
[name]
nome =
[surname]
cognome = topolino
[tag_1]
v#al_1 = a
[tag_2]
val_2 b
[8tag_n]
= n
http://www.guidealgoritmi.it/images/ImgForums/SectionsAutomaton.jpg
#include <iostream>
using namespace std;
#include "SectionsFileAutomaton.h"
int main()
{
string section;
string val_name;
string val;
char *szFileName1 = "C:\\Scaricamenti\\Temp\\tags.txt";
char *szFileName2 = "C:\\Scaricamenti\\Temp\\tags2.txt";
try
{
Automaton myAutomaton(szFileName1);
cout << endl << "File " << szFileName1 << endl;
for ( int k = 0; k < myAutomaton.getNumErrors(); k++ )
cout << endl << myAutomaton.m_errors[k] << endl;
cout << endl;
section = "surname";
val_name = "cognome";
if ( myAutomaton.getValue(section, val_name, val) )
cout << section << " -> " << val_name << " = '" << val << "'" << endl;
else
cout << section << " -> " << val_name << " non trovato." << endl;
cout << endl;
section = "prova";
val_name = "niente";
if ( myAutomaton.getValue(section, val_name, val) )
cout << section << " -> " << val_name << " = '" << val << "'" << endl;
else
cout << section << " -> " << val_name << " non trovato." << endl;
cout << endl;
myAutomaton.readFile(szFileName2);
cout << endl << "File " << szFileName2 << endl;
for ( int k = 0; k < myAutomaton.getNumErrors(); k++ )
cout << endl << myAutomaton.m_errors[k] << endl;
cout << endl;
section = "surname";
val_name = "cognome";
if ( myAutomaton.getValue(section, val_name, val) )
cout << section << " -> " << val_name << " = '" << val << "'" << endl;
else
cout << section << " -> " << val_name << " non trovato." << endl;
cout << endl;
}
catch(AutomatonException ex)
{
cout << ex.getMessage() << endl;
}
return 0;
}
;)
E' analogo al formato dei file INI.
http://it.wikipedia.org/wiki/File_INI
Sotto Windows ci sono gia' delle API che permettono di leggere agevolmente questi tipi di file, essendo che erano i file di configurazione preferiti sotto Windows 3.11 e 95
Esistono tantissimi wrapper che circondano il cuore di queste API, quindi se la tua implementazione e' sotto Windows puoi cercare con google qualcosa tipo
Visual c++ read ini file
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.