Regular Expression

di il
4 risposte

Regular Expression

Salve a tutti,

volevo chiedervi un consiglio sulla sequente regular expression.
Sto utilizzando i metodi matcher and pattern con java, e in una stringa devo prelevare il contenuto
di queste parentesi: (C. 1442-2770-1452) e (A.C. 4144-A), i numeri all'interno possono cambiare, ma cambiano
anche il numero delle cifre ad esempio: (C. 1895) etc...

Io sto procedendo in questo modo

String x = "Hello(JAVA), hi (C. 1442-2770-1452) hello (C. 1685-B) hiiii (A.C. 4144-A)";
Matcher m = Pattern.compile("\\((C.+[0-9])+([-])*?\\)").matcher(x);
Ma stampa soltanto C. 1442-2770-1452
Potreste aiutarmi

Saluti

4 Risposte

  • Re: Regular Expression

    Stai usando alcuni caratteri nel modo sbagliato.
    Innanzitutto il ".", se non è preceduto dal doppio slash, assume il significato di "qualsiasi carattere", anche se solitamente non fa il matching con il carattere di terminazione della linea.
    Poi stai utilizzando delle parentesi tonde che fanno dei raggruppamenti in modo "curioso".

    Dopo la parentesi iniziale (di cui fai correttamente l'escape), raggruppi (con le parentesi tonde), il seguente pattern :

    C.+[0-9]

    Questo significa che cerchi una C iniziale, seguita da una o più occorrenze (+) di qualsiasi carattere (.), seguita poi da una cifra da 0 a 9. Di questo gruppo poi richiedi di avere una o più occorrenze (con il + fuori dalla parentesi).
    Il resto poi non conta, catturi il carattere "-", ma l'asterisco consente di non trovare alcun match.

    Il risultato che trovi (C. 1442-2770-1452) viene trovato perché dopo la "C" iniziale il "." fa il matching dell'intera sequenza ". 1442-2770-145", cioé prende tutto il resto della stringa escluso il "2" finale che viene trovato dal successivo [0-9].
    Ma è quasi un caso

    Intanto fornisci qualche informazione in più : la sequenza può iniziare solo con "C." o con "A.C." come nel tuo esempio? E' seguita poi da uno spazio singolo? In seguito ci sono solo combinazioni di 4 cifre oppure una singola lettera maiuscola, e separati dal "-" ? Possono essere mischiate come capita o la lettera può essere solo alla fine?

    Queste sono solo alcune possibili domande, senza sapere tutto nei dettagli non è possibile trovare una soluzione "sicura".

    Ad esempio il seguente pattern :
    
    Matcher m = Pattern.compile("\\((A\\.)?C\\. ([0-9][0-9][0-9][0-9]|[A-Z])(-([0-9][0-9][0-9][0-9]|[A-Z]))*\\)").matcher(x);
    
    trova i seguenti risultati :
    
    C:\...>java Test
    (C. 1442-2770-1452)
    (C. 1685-B)
    (A.C. 4144-A)
    
    Io ho cercato pattern compresi tra parentesi tonde che inizino con "A." o con "A.C.", seguiti da spazio e dalla combinazione di almeno una sequenza di 4 cifre o una singola lettera maiuscola, le successive (possibili) sequenze devono essere invece precedute da "-".
    Questo pattern dovrebbe trovare anche cose del tipo "(A.C. C-D-0254-B-6525)", quindi servono più dettagli.

    In ogni caso non è una soluzione tanto elegante, ma ad ora non saprei fare molto di meglio.
    Se serve le parentesi iniziali e finali possono essere facilmente rimosse dal risultato (anche se la tua espressione le manteneva), sia manipolando in seguito il risultato (banalmente butti via primo e ultimo carattere) sia direttamente all'interno dell'espressione regolare, utilizzando lookbehind e lookahead.

    Siamo vicini a quello che volevi ?
  • Re: Regular Expression

    Siamo vicinissimi...

    La sequenza può iniziare solo con C. oppure A.C.
    Per quanto riguarda gli spazi, di regola ci deve essere uno spazio bianco, ma è meglio gestirlo anche senza spazi
    Per evitare eventuali bug (A.C.1254-B)
    Di seguito ci sono solo combinazioni di gruppi di 4 numeri, ma il numero dei gruppi non lo conosco esempio (C. 1234),(C. 1234-5678-9101-1121-3141-5161), insomma potrei avere uno svariato numero di valori a gruppi da 4
    La lettera/e possono capitare solo alla fine (A.C 1234-C bis) io dovrei prendere tutto il contenuto delle parentesi anche il bis, ter etc...
    "Questo pattern dovrebbe trovare anche cose del tipo "(A.C. C-D-0254-B-6525)", quindi servono più dettagli." = questo non è ammesso non posso esistere le lettere C-D solo A.C. oppure C.
    Grazie per il lookahead and lookbehind.

    Grazie mille... per l'aiuto !!!!!!!
  • Re: Regular Expression

    manuel__89 ha scritto:


    La sequenza può iniziare solo con C. oppure A.C.
    Per quanto riguarda gli spazi, di regola ci deve essere uno spazio bianco, ma è meglio gestirlo anche senza spazi
    Per evitare eventuali bug (A.C.1254-B)
    Ok, fin qui tutto chiaro e molto semplice da realizzare.

    manuel__89 ha scritto:


    Di seguito ci sono solo combinazioni di gruppi di 4 numeri, ma il numero dei gruppi non lo conosco esempio (C. 1234),(C. 1234-5678-9101-1121-3141-5161), insomma potrei avere uno svariato numero di valori a gruppi da 4
    La lettera/e possono capitare solo alla fine (A.C 1234-C bis) io dovrei prendere tutto il contenuto delle parentesi anche il bis, ter etc...
    Bene per la combinazione di sequenze 4 numeri, in qualsiasi numero.

    Dopo un'eventuale lettera maiuscola (solo alla fine dei numeri) si complica un po' la cosa, nel senso che per permettere cose come "A.C 1234-C bis" bisogna rilassare di molto i vincoli.

    Bene bis e ter, che hanno un senso logico, ma a meno che non sia possibile elencare tutti i possibili valori di queste terminazioni, devi lasciare qualsiasi combinazione di lettere minuscole (magari sei sicuro che saranno solo tre lettere, io nel seguito non farò alcuna ipotesi e catturo un numero qualsiasi di lettere minuscole, dopo uno spazio che lascio eventuale, come hai suggerito per la prima parte).

    Inserendo anche il lookbehind e il lookahead per escludere le parentesi dal match, sono arrivato a questo pattern :

    (?<=\\()(A\\.)?C\\. ?[0-9]{4}(-[0-9]{4})*(-[A-Z])?( ?[a-z]+)?(?=\\))

    Le parti rosse iniziale e finale sono il lookbehind e il lookahead. In arancione l'inizio, che come hai detto può essere solo A.C. o C.
    In nero la parte principale, ovvero la prima sequenza di 4 cifre (obbligatoria!), che può essere preceduta o meno da uno spazio singolo e seguita o meno da un altro qualsiasi numero di sequenze separate da "-".
    In verde la possibile lettera maiuscola (singola), preceduta se presente dal "-".
    In blu la parte per ora più fumosa, con un possibile spazio seguito da un qualsiasi numero di lettere minuscole. Il ? consente che questa parte non ci sia, ovviamente. Con il + dopo le minuscole, invece, ti assicuri che, se lo spazio è effettivamente presente, ci debba essere almeno una minuscola.

    Esempio di utilizzo :
    
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
    public class Test
    {
    	public static void main (String [] a) {
    		String test = "Hello(JAVA), hi (C. 1442-2770-1452) hello (C. 1685-B) hiiii (A.C. 4141-A) blabla (A.C. 4144-A bis) bla"
    					+ "blabla A.C. 4134-A bis) fufu (A.C. 4124-A )lalala (C. 1442-2770-1452-BB)"
    					+ "(C. 1442-2660-1452-B precipitevolissimevolmente) (A.C. 4144-A ter2) (A.C. 4144-0090-9875-5248-7475)"
    					+ "(C.4144-0090-9875-5248-7475)(C.4144-0090-9875-52333-7475) (C. 1777-Bbis)";
    		// Testiamo.
    		System.out.println ();
    		Matcher matcher = Pattern.compile ("(?<=\\()(A\\.)?C\\. ?[0-9]{4}(-[0-9]{4})*(-[A-Z])?( ?[a-z]+)?(?=\\))").matcher (test);
    		while (matcher.find ()) System.out.println (matcher.group ());
    	}
    }
    

    Io ottengo il seguente output :
    
    C:\...>java Test
    
    C. 1442-2770-1452
    C. 1685-B
    A.C. 4141-A
    A.C. 4144-A bis
    C. 1442-2660-1452-B precipitevolissimevolmente
    A.C. 4144-0090-9875-5248-7475
    C.4144-0090-9875-5248-7475
    C. 1777-Bbis
    
    Manca da stabilire appunto la parte finale con le minuscole, per il resto mi pare vada abbastanza bene ...
  • Re: Regular Expression

    Perfetto !!!!
    E' proprio quello che volevo, grazie per la spiegazione, mi serviva proprio.

    Grazie !!!!!!!!!!!!
Devi accedere o registrarti per scrivere nel forum
4 risposte