Soluzione 7.2

La classe Text (piu` sotto la classe TextTester).
La parte piu` impegnativa consiste nella realizzazione del metodo di ordinamento. Abbiamo usato l'algoritmo mergeSort: notare l'uso del metodo ausiliario (e privato) mergeSort, in cui la presenza di parametri espliciti consente di realizzare mergeSort in maniera ricorsiva (mentre il metodo sort, non avendo parametri impliciti, non puo` realizzare direttamente mergeSort in maniera ricorsiva).
import java.util.NoSuchElementException;

public class Text implements Container
{
    public Text()
    {   words = new String[1];
        makeEmpty();;
    }

    /*
        verifica se l'elenco di parole e' vuoto.
        restituisce true se vuoto, false altrimenti
    */
    public boolean isEmpty()
    {   return wordsSize == 0; }
   
    /*
        rende vuoto il contenitore.
    */
    public void makeEmpty()
    {   wordsSize = 0; }

    /*
        restituisce il numero di elementi presenti nel contenitore
    */
    public int size()
    {   return wordsSize; }

    /*
        aggiunge la parola aWord in coda all'elenco
        se l'elenco e' pieno, ridimensiona l'elenco.
    */
    public void add(String aWord)
    {   if (wordsSize == words.length)
            resize();
        words[wordsSize] = aWord;
        wordsSize++;
    }
    private void resize()
    {   String[] newAr = new String[2*wordsSize];
        for (int i = 0; i < wordsSize; i++)
            newAr[i] = words[i];
        words = newAr;
    }

    /*
        ordina per fusione l'elenco delle parole.
    */
    public void sort()
    {   mergeSort(words,wordsSize); }
    private void mergeSort(Comparable[] v, int vSize)
    {   if (vSize < 2) return; // caso base
        int mid = vSize / 2; //dividiamo circa a meta`
        Comparable[] left = new Comparable[mid];
        Comparable[] right = new Comparable[vSize - mid];
        System.arraycopy(v, 0, left, 0, mid);
        System.arraycopy(v, mid, right, 0, vSize-mid);
        // passi ricorsivi: ricorsione multipla (doppia)
        mergeSort(left, mid);
        mergeSort(right, vSize-mid);
        // fusione (metodo ausiliario)
        merge(v, left, right);
    }
    private static void merge(Comparable[] v, Comparable[] v1, Comparable[] v2)
    {  
        int i = 0, i1 = 0, i2 = 0;
        while (i1 < v1.length && i2 < v2.length)
            if (v1[i1].compareTo(v2[i2]) < 0)
                // prima si usa i, poi lo si incrementa...
                v[i++] = v1[i1++];
            else
                v[i++] = v2[i2++];
        while (i1 < v1.length)
            v[i++] = v1[i1++];
        while (i2 < v2.length)
            v[i++] = v2[i2++];
    }

    /*
        restituisce l'ultima parola dell'elenco, rimuovendola
        Lancia NoSuchElementException se l'elenco e' vuoto
    */
    public String removeLast() throws NoSuchElementException
    {   if (isEmpty())
            throw new NoSuchElementException();
        String value = words[wordsSize-1];
        wordsSize--;
        return value;
    }

   // variabili di esemplare
   private String[] words;
   private int wordsSize;
}

La classe TextTester. Le parti piu` rilevanti di questo codice sono l'inserimento di elementi letti da file nel primo oggetto di tipo Text, e l'eliminazione delle parole doppie.
Notare poi l'uso di Scanner con un insieme di delimitatori diverso da quello di default. In particolare si e` usata l'invocazione del metodo useDelimiter di Scanner, fornendo come parametro esplicito la stringa "[\\p{javaWhitespace}\\p{Punct}]+". Il significato di questa stringa e` il seguente: Quelli appena visti sono semplici esempi di espressioni regolari o espressioni canoniche. Chi volesse approfondire l'argomento puo` consultare i Consigli per la produttivita` 8.2 sul libro di testo, e la documentazione della classe Pattern della libreria standard di Java.
import java.io.*;
import java.util.Scanner;

public class TextTester
{   public static void main(String[] args) throws IOException
    {   // verifica degli argomenti sulla riga di comandi
        if (args.length < 1)
        {   System.out.println("uso: $java TextTester filename");
            return;
        }

        // Stampa testo originale
        Scanner in = new Scanner(new FileReader(args[0]));
        System.out.println(in.delimiter());
        System.out.println("\n*** TESTO ORIGINALE ***\n");
        while (in.hasNextLine())
            System.out.println(in.nextLine());
        in.close();

        //lettura file e memorizzazione nel contenitore di testo
        in = new Scanner(new FileReader(args[0]));
        Text text = new Text();
        while (in.hasNextLine())
        {   Scanner linescan = new Scanner(in.nextLine());
            linescan.useDelimiter("[\\p{javaWhitespace}\\p{Punct}]+");
            while (linescan.hasNext())
                text.add(linescan.next());
        }
        in.close();

        // ordinamento lessicografico crescente delle parole del testo
        text.sort();
        int originalTextWordNumber = text.size();

        // eliminazione parole doppie
        Text noRepetitionText = new Text();

        String current = null;
        if(!text.isEmpty())
        {   current = text.removeLast();
            noRepetitionText.add(current);
        }
        while (!text.isEmpty())
        {   String next = text.removeLast();
            if (next.compareTo(current) != 0)
            {   noRepetitionText.add(next);
                current = next;
            }
        }

        // stampa delle parole in ordine lessicografico crescente
        System.out.println("\n***STAMPA DELLE SINGOLE OCCORRENZE***");
        System.out.println(  "*******IN ORDINE LESSICOGRAFICO******");
        System.out.println("Numero parole nel testo originale: "
                            + originalTextWordNumber);
        System.out.println("Numero parole non ripetute: " + 
                            noRepetitionText.size() + "\n");
        while (!noRepetitionText.isEmpty())
            System.out.println(noRepetitionText.removeLast());
    }
}