Java: suddividere una stringa in righe di lunghezza fissa, senza “spezzare” le parole.

Il problema che affrontiamo in questo post è quello di avere una lunga stringa che deve essere visualizzata su diverse righe di lunghezza fissa. Dobbiamo quindi suddividere questa stringa in più stringhe, rispettando la lunghezza massima definita per le righe e, soprattutto, mantenendo le parole intere senza spezzarle quando si è raggiunta la fine della riga. Inoltre dobbiamo anche tenere conto della punteggiatura ed evitare di andare a capo qualora il carattere n+1 sia un punto, una virgola, un punto interrogativo, ecc..
Per farlo utilizziamo un’espressione regolare e le classi che Java mette a disposizione per il loro utilizzo, ovvero Pattern e Matcher. Per evitare che le parole vengano troncate a metà quando si raggiunge la fine della riga, dobbiamo delimitare il nostro pattern di ricerca con dei word boundaries (\b).
Inoltre, dobbiamo limitare la lunghezza del pattern da cercare ad n-1 e lasciare lo spazio per un eventuale segno di punteggiatura.
Creiamo un metodo statico che prende come parametri la stringa da splittare e la lunghezza massima della riga e restituisce una lista di stringhe rappresentanti appunto le righe. La signature del metodo sarà quindi la seguente:

public static List splitString(String msg, int lineSize)

Di seguito il codice del programma ed il test su una stringa di esempio:

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class CutString {

    public static List<String> splitString(String msg, int lineSize) {
        List<String> res = new ArrayList<>();

        Pattern p = Pattern.compile("\\b.{1," + (lineSize-1) + "}\\b\\W?");
        Matcher m = p.matcher(msg);
        
	while(m.find()) {
                System.out.println(m.group().trim());   // Debug
                res.add(m.group());
        }
        return res;
    }

    public static void main(String[] args) {

	splitString("Questo è un messaggio che deve essere splittato su più righe perchè è troppo lungo. Il risultato prodotto deve essere una serie di stringhe della lunghezza massima fornita come input. Funzionerà questa procedura? Spero di si!", 40);
    }

}

L’output generato, in questo caso, è il seguente:

Questo è un messaggio che deve essere
splittato su più righe perchè è troppo
lungo. Il risultato prodotto deve
essere una serie di stringhe della
lunghezza massima fornita come input.
Funzionerà questa procedura? Spero di
si!

Come possiamo vedere, le parole sono state mandate a capo correttamente, senza essere spezzate a metà in caso del raggiungimento della dimensione massima della riga a metà parola. Effettuiamo qualche ulteriore test sui casi limite, ad esempio nel caso in cui un carattere di punteggiatura sia nell’ultima posizione disponibile della riga e nel caso in cui tale carattere sia invece il primo successivo al limite della riga:

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class CutString {

    public static List<String> splitString(String msg, int lineSize) {
        List<String> res = new ArrayList<String>();

        Pattern p = Pattern.compile("\\b.{1," + (lineSize-1) + "}\\b\\W?");
        Matcher m = p.matcher(msg);
        while(m.find()) {
                System.out.println(m.group().trim());   // Debug
                res.add(m.group());
        }
        return res;
    }

    public static void main(String[] args) {
	
        splitString("In questo caso un carattere speciale compare come ultimo elemento della stringa!", 80);
	System.out.println("----");
        splitString("In questo caso un carattere speciale compare come primo elemento dopo la stringa!", 80);
    }

}

Ecco il risultato di questa nuova esecuzione:

In questo caso un carattere speciale compare come ultimo elemento della stringa!
----
In questo caso un carattere speciale compare come primo elemento dopo la
stringa!

Come possiamo vedere, nel primo caso, il punto esclamativo ha occupato l’ultimo spazio disponibile nella riga, mentre nel secondo caso, il ‘!’ avrebbe rappresentato il primo carattere della riga successiva. Invece, correttamente, la prima riga è terminata con la parola precedente e l’ultima parola ed il carattere ‘!’ sono finiti entrambi nella seconda riga.

Leave a Reply

Your email address will not be published. Required fields are marked *