Inserimento più attributi in una stringa

di il
18 risposte

Inserimento più attributi in una stringa

Ciao a tutti ragazzi.

vi spiego:

la lettura da un file di testo "listautenti.txt" avviene solo se il file è composto da stringhe ordinate del tipo nome - cognome - anno - tag
es Paperone - De Paperoni - 1946 - soldi

Ma il compito d'esame mi richiede che il file accetti un numero >=0 di tag non definiti a priori.
In sintesi dovrei renderlo in grado di leggere un file di testo composto così:

Pico - De Paperis - 1965 - storia - geografia - paperopoli - scienze
Paperone - De Paperoni - 1946 - soldi
Gastone - Comesichiama - 1968

Il codice che ho scritto finora va in errore(noSuchFile) se il file non è formattato con un solo tag
mi potreste aiutare a risolvere il problema?


import java.util.ArrayList;
import java.util.Scanner;
import java.util.StringTokenizer;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;


public class UtenteMain {


    public static void main(String[] args) {
        ArrayList<Utente>listaUtenti=new ArrayList<Utente>();


        try{ 
                    //inizializzazione strumenti lettura
            FileReader fr=new FileReader("listautenti.txt");
            BufferedReader br=new BufferedReader(fr);


                    //lettura del file riga per riga
            String rigaLetta = br.readLine( );
            while(rigaLetta!=null)
            {
                StringTokenizer st=new StringTokenizer(rigaLetta, "-");
                String nome=st.nextToken();
                String cognome=st.nextToken();
                String anno=st.nextToken();
                String listaTag=st.nextToken();
                try{
                    Utente temp=new Utente(nome,cognome,anno,listaTag);
                    listaUtenti.add(temp);
                }
                catch( NumberFormatException e )
                {
                    System.out.println( "Errore DA DECIFRARE NEL CODICE: " + rigaLetta + "; record" );
                }


                rigaLetta = br.readLine( );


            }
            br.close( );


                    // stampa a video la lista completa (temporaneamente)
            for ( Utente elementi: listaUtenti )
                //if (elementi.nome.equalsIgnoreCase("Mario")) per fare una selezione sulla stampa
                System.out.println(elementi.nome +" "+  elementi.cognome+ " "+ elementi.anno+" "+ elementi.listaTag); 


        }catch(FileNotFoundException e){
            System.out.println("Errore -file non trovato");


        }catch(IOException e){
            System.out.println("Errore nella lettura file(corrotto)");
        }
    }
}

18 Risposte

  • Re: Inserimento più attributi in una stringa

    Avevi già chiesto qui su html.it e ti avevo già ampiamente risposto.
  • Re: Inserimento più attributi in una stringa

    Purtroppo non sono riuscito a capire l'impostazione dell'arraylist come "argomento" e la successiva aggiunta nei tag andbin!
    Altrimenti non chiederei una mano anche qui

    qualcuno mi potrebbe dare una mano?
  • Re: Inserimento più attributi in una stringa

    cicciozza ha scritto:


    Purtroppo non sono riuscito a capire l'impostazione dell'arraylist come "argomento" e la successiva aggiunta nei tag andbin!
    Altrimenti non chiederei una mano anche qui

    qualcuno mi potrebbe dare una mano?
    A me pare che la spiegazione fornita nella discussione linkata sia abbastanza chiara, hai provato a creare l'arraylist e ad inserire i tag? Se sì cosa non ti è riuscito? Prova a postare una tua soluzione al problema, per ora il codice che hai linkato non sfrutta nulla di ciò che ti è stato consigliato...
    
    Utente temp=new Utente(nome,cognome,anno,listaTag);
    
    Questa riga è il succo del problema: cosa vuoi che sia quel listaTag? Un array ? Una lista (es. ArrayList) ? Una stringa ? Altro ?
    Per le prime due soluzioni se segui quanto detto hai già la traccia di quello che devi fare :

    1- Se vuoi una lista dei tag rimanenti, dopo aver letto anno, crei una lista (all'inizio è vuota ovviamente), poi utilizzi hasMoreTokens() in un ciclo per aggiungere ogni successivo token che andrai a leggere con nextToken().
    2- Se vuoi un array dovresti conoscere a priori quanti sono i tag che andrai a leggere dopo anno, a meno di non volere creare un array con una dimensione sufficientemente grande per poter contenere quanto andrai a leggere (soluzione abbastanza orrenda e pericolosa).
    Per conoscere la dimensione, come ti è stato detto, puoi usare countTokens(), poi il ciclo con nextToken() sarà quasi identico, cambia solo il modo di aggiungere la stringa alla struttura dati.
    3- Usare una stringa contenente tutti i tokens rimanenti non è l'ideale (soprattutto in questo esercizio), è tanto per dire che le prime due soluzioni non sono le uniche, possono essercene altre. Una stringa unica sarebbe l'equivalente di un campo "descrizione" che si trova in alcuni contesti. Potresti leggere i primi tre tokens (o la parte fissa) e poi prendere tutto il resto della stringa.
    Oltre a non essere una buona soluzione è anche più artificiosa perché sei costretto a calcolare la lunghezza dei primi tre campi per poter sapere da dove devi 'tagliare' la stringa (ad esempio con substring()) per prendere tutto il resto dei tag.

    A questo punto tocca a te chiarire cosa vuoi fare e provare a scrivere la soluzione, poi in caso di bisogno siamo qui
  • Re: Inserimento più attributi in una stringa

    Cercherò di essere chiaro

    Non riesco a "dividere" la lettura degli attributi di tipo stringa dall'attributo tag.
    Non capisco poi come, a lettura ultimata di nome cognome e anno devo fargli acquisire questa listaTag (di lunghezza imprecisata).

    Avevo impostato il programma in modo che un tag fosse compreso nella lettura (come stringa) e fin li tutto bene.
    Quando mi complico la vita con la listaTag come arrayList( mi pare di aver capito che non posso farne realmente a meno) mi perdo definitivamente.
    Il problema è che non capisco "logicamente" come fargli fare le letture, come impostare i while, se posso continuare a usare lo StringTokenizer o devo cambiare anche quello.

    Scusatemi, non voglio annoiarvi ma non riesco proprio a procedere :S
  • Re: Inserimento più attributi in una stringa

    cicciozza ha scritto:


    Non riesco a "dividere" la lettura degli attributi di tipo stringa dall'attributo tag.
    Ascolta, cerco di ripeterlo meglio rispetto a quanto detto su html.it

    Se hai degli attributi fissi (es. 3) che ti aspetti esistano sempre, è corretto fare una nextToken() "secca" per ciascuno di questi attributi. Se dovesse sbucare un NoSuchElementException estraendo questi attributi fissi, è il segno che il file (la riga perlomeno) è "malformato". Cioè è un errore tra virgolette "grave" che vuol dire che il file non rispetta le specifiche richieste o imposte. Dovresti quindi catturare NoSuchElementException in questa parte e a quel punto puoi: a) ignorare la riga (salti a quella successiva), oppure b) terminare tutta la gestione del file (chiaramente come fallimento del programma).

    Mentre invece per gli attributi variabili ci sono diverse opzioni. Innanzitutto ce ne possono essere un numero arbitario. NON è un problema, li tieni o in un array String[] oppure in un ArrayList<String>. La differenza è che un array lo devi dimensionare a priori mentre un ArrayList (come le altre collezioni) si espande automaticamente aggiungendo elementi.

    Nell'altra discussione ti avevo anche detto che StringTokenizer ha anche countTokens(), questo ti permette di sapere a priori quanti token rimangono da estrarre in un qualunque momento:

    Quindi, DOPO aver letto i token "fissi" puoi:

    1) usare countTokens(), sai quindi quanti token rimangono, pertanto istanzi un nuovo array new String[num] (num, numero token rimanenti) e poi fai un banale for in cui estrai un token e lo inserisci alla posizione i-esima dell'array.

    OPPURE

    2) istanzi una nuova lista, new ArrayList<String>(), nota NON hai bisogno di sapere a priori quanti token restano. Poi fai un while usando hasMoreTokens() come condizione. Ovvero "finché c'è ancora un token", lo estrai. E lo aggiungi nel ArrayList.

    Tutto qui.
  • Re: Inserimento più attributi in una stringa

    cicciozza ha scritto:


    Cercherò di essere chiaro

    Non riesco a "dividere" la lettura degli attributi di tipo stringa dall'attributo tag.
    Non capisco poi come, a lettura ultimata di nome cognome e anno devo fargli acquisire questa listaTag (di lunghezza imprecisata).

    Avevo impostato il programma in modo che un tag fosse compreso nella lettura (come stringa) e fin li tutto bene.
    Quando mi complico la vita con la listaTag come arrayList( mi pare di aver capito che non posso farne realmente a meno) mi perdo definitivamente.
    Il problema è che non capisco "logicamente" come fargli fare le letture, come impostare i while, se posso continuare a usare lo StringTokenizer o devo cambiare anche quello.

    Scusatemi, non voglio annoiarvi ma non riesco proprio a procedere :S
    Ma quasi tutte le risposte che cerchi sono già state date!

    Devi usare sempre lo stesso StringTokenizer, perché è lui a sapere a quale token è arrivato dopo aver letto nome, cognome e anno. Poi devi solo fare un ciclo con quell'oggetto per leggere i tokens rimanenti.
    Hai cercato un attimo online come si usa hasMoreTokens() ? Ti basterebbe davvero un secondo per risolvere il problema, non puoi aspettarti che ti scriviamo noi il codice, altrimenti non impari!

    Tra l'altro basta leggere la documentazione di StringTokenizer (https://docs.oracle.com/javase/7/docs/api/java/util/StringTokenizer.html) per trovare un esempio MOLTO simile al tuo, guarda le righe che riporto :
    The following is one example of the use of the tokenizer. The code:

    StringTokenizer st = new StringTokenizer("this is a test");
    while (st.hasMoreTokens()) {
    System.out.println(st.nextToken());
    }

    prints the following output:

    this
    is
    a
    test
    Nel caso in esame tutti i token di "this is a test" vengono stampati a video. Tu vuoi invece aggiungerli a una lista (o altro), ti basta creare la lista fuori dal ciclo e aggiungere ogni singolo elemento.
    Ora devi fare tu un passetto avanti
  • Re: Inserimento più attributi in una stringa

    Ok, a parole mi sembra un attimo più chiaro.
    Vado a mettere le chiappe sulla sedia e vi aggiorno
  • Re: Inserimento più attributi in una stringa

    try{ 
    			//inizializzazione strumenti lettura
    			FileReader fr=new FileReader("listautenti.txt");
    			BufferedReader br=new BufferedReader(fr);
    
    					//lettura del file riga per riga
    			String rigaLetta = br.readLine( );
    			while(rigaLetta!=null)
    			{
    				
    				StringTokenizer st=new StringTokenizer(rigaLetta, "-");
    				String nome=st.nextToken();
    				String cognome=st.nextToken();
    				String anno=st.nextToken();
    				
    				//adesso devo dirgli che finchè ha dei tag li deve leggere e aggiungere a "tag".
    				
    				while(st.hasMoreTokens())
    				{
    				rigaLetta=st.nextToken();
    				for (int i=0;i<4 ;i++)
    				tag.add(rigaLetta);
    //TAG CANNOT BE RESOLVED
    
    				System.out.println(st.nextToken());
    				}
    				
    
    				try{
    					ArrayList <String>tag=new ArrayList <String>();
    					Utente temp=new Utente(nome,cognome,anno,tag); 
     //QUI MI DA ERRORE PERCHè NON RICONOSCE TAG COME ATTRIBUTO
     
     
     
    					listaUtenti.add(temp);
    				}
    				catch( NumberFormatException e )
    				{
    					System.out.println( "Errore DA DECIFRARE NEL CODICE: " + rigaLetta + "; record" );
    				}
    
    				rigaLetta = br.readLine( );
    
    			} 
    			br.close( );
    Ragazzi sto facendo una marea di prove.
    Un altra ora che sbatto la testa e non capisco.
    Non voglio star sempre li a contestare il vostro metodo e apprezzo davvero l'aiuto ma credo seriamente che in questo caso, la soluzione sputata con un bel " STAI SBAGLIANDO qui, perchè si fa in questo modo" sia la più semplice perchè da li imparo come si risolve(subito) il problema e vado avanti!


    Sono giorni che provo senza arrivare a soluzioni, non sto cercando di fare il furbetto, credetemi!
    proverò a fare qualche lezione privata, pazienza.
    Buona giornata a tutti
  • Re: Inserimento più attributi in una stringa

    Beh ma dal codice che hai postato sembri non avere per niente le idee chiare, non solo relativamente al problema di aggiungere tutti i tag successivi a nome, ma in generale sui fondamenti del linguaggio!

    Andiamo passo a passo nel tuo codice, partendo dal punto in cui hai letto anno come token. Tu dici giustamente che finché ha dei tag li deve leggere e aggiungere a "tag". Poi inizi il ciclo con while(st.hasMoreTokens()).

    Questo è il primo errore. Ti abbiamo detto entrambi che la lista va creata prima del ciclo, mentre tu all'interno usi tag.add(...) senza aver prima creato l'arraylist tag, che crei successivamente. Ovviamente a quel punto del codice il programma non può sapere cosa sia tag!
    Quindi sposta la riga :
    
    ArrayList <String>tag=new ArrayList <String>();
    
    prima di entrare nel while.

    Secondo errore: dentro al while non ha alcun senso il for innestato che hai inserito. Il ciclo esterno sta già ciclando su ogni token, quindi basta aggiungere "rigaLetta" all'arraylist una volta, mentre tu lo stai facendo 4 volte.
    Il for avrebbe senso di esistere se sapessi il numero di tokens da leggere (avendo prima utilizzato countTokens()), ma se usi quello non hai bisogno di utilizzare anche il ciclo con st.hasMoreTokens(). Quindi o utilizzi uno, o utilizzi l'altro, per ora rimuovi semplicemente il for.
    
    ArrayList <String>tag=new ArrayList <String>();
    Utente temp=new Utente(nome,cognome,anno,tag); 
    //QUI MI DA ERRORE PERCHè NON RICONOSCE TAG COME ATTRIBUTO
    
    Puoi sapere solo tu cosa si aspetta di ricevere il costruttore di utente. Se passi tre stringhe e un arraylist di stringhe come argomenti deve necessariamente esserci un costruttore definito in Utente come :
    
    public Utente(String s1, String s2, String s3, ArrayList<String> list) {
    //...
    }
    
    Ovviamente i nomi li scegli tu, ma i tipi devono coincidere. Ma senza sapere questa cosa non vai assolutamente avanti!

    Se con questi consigli non riesci ancora a sistemare il codice vuol dire che probabilmente l'esercizio è a un livello per ora troppo difficile, hai tutte le informazioni necessarie, scriverti direttamente il codice andrebbe contro il tuo interesse!
  • Re: Inserimento più attributi in una stringa

    import java.util.ArrayList;
    
    public class Utente {
    
    	public String nome;
    	public String cognome;
    	public String anno;
    	public ArrayList<String> tag=new ArrayList<String>();
    	
    	
    	public Utente(){
    		
    	}
    	
    	public String getNome() {
    		return nome;
    	}
    public void setNome(String nome) {
    		this.nome = nome;
    	}
    public String getCognome() {
    		return cognome;
    	}
    public void setCognome(String cognome) {
    		this.cognome = cognome;
    	}
    public String getAnno() {
    		return anno;
    	}
    public void setAnno(String anno) {
    		this.anno = anno;
    	}
    public ArrayList<String> getTag() {
    		return tag;
    	}
    public void setTag(ArrayList<String> tag) {
    		this.tag = tag;
    	}
    public void addTag(String tag){
    	this.tag.add(tag);
    }
    
    
    Questa è la classe utente.
    C'è qualcosa che non va ?
    Perchè continua a darmi errore quando vado a creare un nuovo utente "temp" ?
  • Re: Inserimento più attributi in una stringa

    Rileggi quanto ho scritto sopra, se tu istanzi un Utente passando 4 parametri, nella classe Utente deve esserci un costruttore che prende in ingresso 4 parametri, inoltre il tipo di ogni parametro deve essere uguale a quello che poi gli passi, altrimenti avrai sempre un errore in compilazione.
    Tu al momento in Utente hai solo un costruttore vuoto (senza argomenti), quindi al momento non puoi utilizzare quel tipo di dichiarazione.

    Nel messaggio precedente c'è già l'esempio di come dovresti dichiarare il costruttore in Utente, con i 4 parametri specificati.
    Ti manca solo assegnare ai campi di Utente quello che viene passato nel costruttore, come fai nei metodi set per essere chiari (solo che nel set fai l'assegnazione di un singolo campo, ora dovresti semplicente assegnare tutti e 4 i campi ).
  • Re: Inserimento più attributi in una stringa

    cicciozza ha scritto:


    Questa è la classe utente.
    C'è qualcosa che non va ?
    Quasi ok. I campi (variabili di istanza) vanno tenuti private.

    Solo per certi tipi di design (e specialmente se è implicata una gerarchia di classi), si può mettere protected. E praticamente mai (0,000001%) si mette public.

    Il addTag ok ma non è strettamente obbligatorio lì.

    cicciozza ha scritto:


    Perchè continua a darmi errore quando vado a creare un nuovo utente "temp" ?
    Dipende ovviamente dal resto ... non dalla classe Utente in sé.
  • Re: Inserimento più attributi in una stringa

    
    public class Utente {
    
    	public String nome;
    	public String cognome;
    	public String anno;
    	public ArrayList<String> tag=new ArrayList<String>();
    	
    	
    	public Utente(String nome,String cognome,String anno,ArrayList tag){
    		this.nome=nome;
    		this.cognome=cognome;
    		this.anno=anno;
    		this.tag=tag;
    	}
    	
    Questa è la modifica alla classe utente.

    qui sotto metto quella al try nel main
    
    				try{
    				
    					
    					Utente temp=new Utente(nome,cognome,anno,tag);
    					listaUtenti.add(temp);
    				}
    				catch( NumberFormatException e )
    sembrano spariti gli errori ma
    adesso mi va in nosuchelementexception
  • Re: Inserimento più attributi in una stringa

    cicciozza ha scritto:


    
    				try{
    				
    					
    					Utente temp=new Utente(nome,cognome,anno,tag);
    					listaUtenti.add(temp);
    				}
    				catch( NumberFormatException e )
    In questo pezzo di codice NULLA è di fatto in grado di lanciare NumberFormatException, quindi questo try-catch è assolutamente inutile. Tecnicamente è lecito metterlo perché NumberFormatException è una eccezione "unchecked", quindi non c'è alcun obbligo né di dichiararlo né di catturarlo.

    E se questo è l'unico try-catch che hai messo, allora probabilmente il resto del codice è sguarnito di un try-catch su NoSuchElementException che magari sarebbe più utile.

    Io ti assicuro che è più semplice e meno contorto di quanto hai fatto finora.
Devi accedere o registrarti per scrivere nel forum
18 risposte