mercoledì 20 ottobre 2010

API - Pattern

Le classi per lavorare su pattern in Java sono:

  • Pattern e Matcher e String.split per lavorare su stringhe;
  • Formatter e Scanner per lavorare su stream.
Quando si cerca un determinato pattern all'interno di una stringa si possono usare le regular expression; per usarle si crea un Pattern con l'espressione da cercare, e poi si cerca su un testo:
    Pattern p = Pattern.compile("o."); // the expression
    Matcher m = p.matcher("ciao mondo"); // the source
    while(m.find()) {
        System.out.println(m.start() + " " + m.end() + " <" + m.group() + ">");
    }
stampa
    3 5 <o >
    6 8 <on>
I metodi Matcher.start() restituisce la posizione attuale nel Matcher (dove è stato trovato il match attuale), Matcher.end() restituisce la posizione finale, e Matcher.group() restituisce l'intero contenuto. Il metodo Matcher.group() permette anche di scegliere il sottogruppo ricercato, nel caso di espressioni regolari più complesse; guardiamo l'esempio seguente:
    Pattern p = Pattern.compile("(.)(o)(.)"); // the expression
    Matcher m = p.matcher("ciao mondo"); // the source
    while(m.find()) {
        System.out.println(m.start() + " " + m.end() + " <" + m.group(1) + " - " + m.group(2) + " - " + m.group(3) + ">"); 
    }
restituisce:
    2 5 <a - o -  >
    5 8 <m - o - n>
poiché l'espressione (.)(o)(.) trova tutte le posizioni dove abbiamo una 'o' circondata da due caratteri, e poi divide il risultato in tre gruppi, da cui 'a', 'o', ' ' in "ciao ".

Il passo successivo consiste nell'utilizzare i metacaratteri; disponiamo dei seguenti:
  • \d - trova i digits, cioè cifre da 0-9
  • \w - trova le word, cioè i caratteri (lettere (tra 'a' e 'z') e (tra 'A' e 'Z') e (tra 0 e 9) o '_')
  • \s - trova gli spazi (' ', '\n', '\r', '\t')
oppure possiamo usare le '[' e ']' per racchiudere range di caratteri, per esempio \d è uguale a [0-9] e \w è uguale a [a-zA-Z0-9_]; possiamo usare i quantificatori per indicare quanti elementi vogliamo cercare: se usiamo '+' indichiamo (almeno una), se usiamo '*' indichiamo (tra zero e infinito) e se usiamo '?' indichiamo (o zero o una); se usiamo [^abc] indichiamo (qualsiasi tranne 'a', 'b' o 'c'); se vogliamo indicare un carattere qualsiasi possiamo usare '.'; infine se vogliamo fare ricerche non golose usiamo '*?' al posto di '*' e '?+' al posto di '+'; la differenza tra golose e non è che le golose cercano il match più ampio, mentre le non golose cercano il minore; un esempio è
Pattern greedy: .*xx
Pattern non greedy: .*?xx
Stringa: yyxxxyxx
il match greedy (goloso) da come risultato "yyxxxyxx", mentre il match non greedy da come risultato yyxx e xyxx

Come Matcher, anche Scanner permette di fare ricerche, lavorando su Stream (o su File o su Stringhe):
    Scanner s = new Scanner("ciao mondo");
    String token;
    do {
        token = s.findInLine("(.)(o)(.)");
        System.out.println("found <" + token + ">");
    } while (token != null);

Scanner normalmente viene utilizzato per fare il "tokenizing"; l'alternativa è usare String.split(); vediamo intanto questo e poi come fare con Scanner:
    String [] str = "ciao mondo sono molto felice".split(".o.");
    for (String s : str)
        System.out.print(s + " - ");
che restituisce
ci -  -  -  - o  -  - felice - 
Mentre otteniamo la stessa funzione dello scanner, abbiamo spesso una funzionalità non richiesta: lui esegue il tokenizing di tutta la stringa prima di darci un output; quando questo non è il comportamento desiderato basta utilizzare lo Scanner (che funziona anche su Stream e File, e restituisce tipo primitivi):
    Scanner s = new Scanner("ciao 123 cmondo true sdada");
    while(s.hasNext()) {
    if (s.hasNextInt())
        System.out.print("Intero(" + s.nextInt() + "); ");
    else if (s.hasNextBoolean())
        System.out.print("Boolean(" + s.nextBoolean() + "); ");
    else
        System.out.print(s.next() + "; ");
    }
restituisce:
ciao; Intero(123); cmondo; Boolean(true); sdada; 

Abbiamo infine l'oggetto Formatter che ci fornisce i metodi printf e format che si comportano così:
...

Il codice è qui

Nessun commento:

Posta un commento