/***  LETTURA DA STANDARD INPUT DI CARATTERI
      --------------------------------------


Scrivere un programma che legge da standard input una sequenza di caratteri
e stampa il numero delle lettere e il numero totale dei caratteri letto.




InputStreamReader
-----------------

Per leggere una sequenza di caratteri, e' sufficiente definire un oggetto di classe

     java.io.InputStreamReader


Dato che i caratteri vengono letti da standard input, l'oggetto va creato 
mediante la chiamata


   new InputStreamReader(System.in)
  

dove System.in si riferisce al flusso  (stream) di caratteri che rappresenta lo standard input.  

La  classe InputStreamReader  dispone del metodo


   public int read() throws IOException


che legge un singolo carattere e restituisce il carattere letto 
oppure -1 se si e' raggiunta la fine dello stream di input.

Notare che  read restituisce un elemento di tipo int e non di tipo char,
perche' il numero -1 non e' rappresentabile come char.
Infatti, il tipo char ha dimensione di 16 bit e  permette di rappresentare gli interi n>=0 
che  in base 2 hanno  al massimo 16 cifre (codici dei caratteri Unicode).


Il metodo read puo' sollevare un'eccezione controllata di tipo IOException in caso di errore.
Dato che non ci preoccupiamo di gestire l'eccezione, nell'intestazione del metodo main
occorre scrivere:

   public static void main(...) throws IOException
      ...

altrimenti si ha errore in compilazione.



REDIREZIONE DELLO STANDARD INPUT
--------------------------------

Lo standard input e' un flusso (stream) di caratteri e per default 
lo standard input contiene i caratteri inseriti  tramite la tastiera.

L'interprete dei comandi (shell) permette di redirigere  lo standard input da un  file. 
Questo significa che viene interrotto il collegamento fra standard input e tastiera
e i caratteri vengono letti  dal file specificato.

Per redirigere lo standard input  occorre scrivere dopo il comando
il simbolo '<' e il nome del file da cui si vuole redirigere l'input.


ESEMPIO
-------

Supponiamo che il file in1.txt contenga le linee

------ FILE in1.txt ------
Quanti caratteri
ci  sono in
questo file?

E quante lettere?
------ FINE FILE in1.txt ------


Dando il comando

  
  java  EsempioLetturaCaratteri  < in1.txt

viene stampato

  Numero caratteri: 61
  Numero lettere: 47


Infatti, il file in1.txt contiene 47 lettere e 14 caratteri di altro tipo 
(2 punti di domanda, 7 spazi, 5 new-line).  
 
Per vedere tutti i caratteri si puo' usare il comando od (octal dump).


  od -b in1.txt

Visualizza il contenuto di in1.txt mostrando il codice di tutti caratteri in base 8.
Vengono visualizzati 16 caratteri per linea, la prima colonna conta i caratteri (in base 8).



0000000 121 165 141 156 164 151 040 143 141 162 141 164 164 145 162 151
0000020 012 143 151 040 040 163 157 156 157 040 151 156 012 161 165 145
...........


Ad esempio, 121 in base 8 rappresenta il numero 81, che corrisponde a 'Q';
012  in base 8 rappresenta il numero 10, che corrisponde al new-line.

Con ozione '-a':

  od -a in1.txt

i caratteri sono visualizzati (sp=spazio, nl=new-line):

0000000   Q   u   a   n   t   i  sp   c   a   r   a   t   t   e   r   i
0000020  nl   c   i  sp  sp   s   o   n   o  sp   i   n  nl   q   u   e
...........




La redirezione e' fatta dalla shell e il programma non e' consapevole del fatto
che lo standard input sia associato a tastiera o a un file.


TERMINAZIONE DELLO STREAM DI CARATTERI
--------------------------------------

Il metodo read restituisce -1 quando viene  raggiunto il termine dello stream di caratteri.

- Se l'input e' rediretto da un file, lo stream termina quando viene raggiunta la fine del file.

- Se l'input e' inserito da tastiera, la terminazione va comunicata tramite un apposito segnale,
  chiamato EOF (end of file). In genere  EOF  si ottiene inserendo ^D,
  cioe' premendo contemporaneamente il tasto <Ctrl> e il tasto <D> (minuscolo).

NOTA
----

Non confondere ^D  (fine input)  con  ^C (termina l'esecuzione di un programma).


REDIREZIONE DELLO STANDARD OUTPUT
---------------------------------

Lo standard output e' lo stream su cui vengono scritti i caratteri stampati
dal programma.

Per default  i caratteri sullo standard output vengono visualizzati sullo schermo.

E' possibile redirigere lo standard output di un comando  tramite il carattere '>'
seguito dal nome del file in cui si vuole redirigere l'ouptut. 
L'output del comando viene scritto nel file specificato.



ESEMPIO
-------

Il  comando 'date' stampa la data corrente.

Scrivendo

 date > d.txt

l'output  viene scritto nel file d.txt.

Per leggere d.txt si puo' fare ad esempio:

 less d.txt


oppure

 cat d.txt


ATTENZIONE
---------

Se esiste gia' un file di nome d.txt, il vecchio  contenuto di d.txt viene perso.

ESEMPIO
-------

Il comando echo scrive su standard output i suoi argomenti.

Facendo

  echo a  12  b  > d.txt

l'output di echo  viene rediretto in d.txt, cancellando il suo contenuto.

Se non si vuole perdere il contenuto di d.txt:

  echo a 12 b  >>  d.txt

L'output del comando viene scritto  in coda a d.txt.




-----


Provare a eseguire



java  EsempioLetturaCaratteri  < in1.txt   > out1.txt
 

dove in1.txt e' il file definito sopra.


USO DI ASSEGNAMENTI NELLA CONDIZIONE DI UN CICLO
================================================

L'istruzione
  
  int c;

  while( ( c = rd.read() ) != -1) {
        <istruzioni>
  }


  equivale a:

 
  c = rd.read();
  while(c != -1) {
      <istruzioni>
      c = rd.read();
  }

 
 Infatti, la valutazione della  condizione

  ( c = rd.read() ) != -1

  avviene come segue:  

 1) Viene eseguito l'assegnamento 

    c = rd.read() 

 2) Viene valutato il valore della condizione

     c != -1

Le parentesi che racchiudono l'assegnamento  sono necessarie,
altrimenti l'espressione verrebbe interpretata come

(*)    c =  (rd.read() !=  -1)
 
in quanto l'operatore '!=' ha priorita' maggiore di '='.
L'espressione (*)  ha senso solo se c ha tipo boolean.



***********/


import java.io.*;  

public class  EsempioLetturaCaratteri {

    public static void main(String[] args) throws  IOException {
       
        InputStreamReader rd = new InputStreamReader(System.in);

	int count = 0; // conta tutti i caratteri 
	int countLettere = 0; // conta le lettere

	int c;  // carattere letto (c deve avere tipo int, non char!)

	while(( c = rd.read() ) != -1){  // il ciclo termina quando c vale  -1 (= fine input)
	    count++;
	    if( (c >= 'a' && c<= 'z') ||  (c >= 'A' && c<= 'Z'))      
             // OPPURE:	 if(Character.isLetter(c))		
		countLettere++;
	}
	
       	System.out.println("Numero caratteri: " + count );
       	System.out.println("Numero lettere: " + countLettere );
	

    }// end main

}// end class
