PDA

View Full Version : [C++] Lettura file testo con tag


Unrue
22-09-2008, 16:43
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. ;)

Tommo
23-09-2008, 00:24
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?

Unrue
23-09-2008, 11:18
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 "]"

Unrue
23-09-2008, 13:03
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 ;)

Tommo
23-09-2008, 14:31
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.

marco.r
23-09-2008, 14:32
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.

marco.r
23-09-2008, 14:34
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;
}


;)

gugoXX
23-09-2008, 23:45
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