2009-09-29 18 views
5

Quello che mi serve è controllare se una determinata stringa corrisponde parzialmente a una determinata espressione regolare. Ad esempio, per la regex ab[0-9]c, le stringhe "a", "ab", "ab3" e "b3c" sarebbero "corrispondenti", ma non le stringhe "d", "abc" o "a3c". Quello che ho fatto è il clunky a(?:b(?:[0-9](?:c)?)?)? (che funziona solo per alcune delle corrispondenze parziali, in particolare quelle che "iniziano" per corrispondere), ma poiché questo fa parte di un'API, preferirei dare agli utenti un aspetto più intuitivo modo di inserire le loro espressioni regolari corrispondenti.Esiste un modo elegante per eseguire corrispondenze regolari di espressioni regolari in Java?

Nel caso in cui la descrizione non sia molto chiara (e mi rendo conto che potrebbe non esserlo!), Questa verrà utilizzata per convalidare l'immissione di testo su caselle di testo. Voglio impedire qualsiasi modifica che si tradurrebbe in una stringa non valida, ma non posso semplicemente abbinare la stringa a una regolare espressione regolare, poiché finché non viene immessa completamente, non corrisponderà. Ad esempio, utilizzando la regex sopra (ab[0-9]c), quando tento di inserire 'a', non è consentito, poiché la stringa "a" non corrisponde alla regex.

Fondamentalmente, è una sorta di inversione startsWith() che funziona su espressioni regolari. (new Pattern("ab[0-9]c").startsWith("ab3") dovrebbe restituire true.)

Qualche idea?

+0

FYI: 'un (:? B? (:?? [0-9] (?: c)))?' Corrisponderà * qualsiasi stringa * che contiene una "a", come "il jazz ". Si desidera usare '^ a (?: B (?: [0-9] (?: c)?)?)? $' In modo che si corrisponda all'intera stringa. – Kip

+0

Tutte le espressioni regolari utilizzate dal client sono semplici come "ab [0-9] c', o sarà necessaria una corrispondenza più complessa (cioè con sottogruppi)? – Kip

+0

Oops ... sì, il^e $ vengono aggiunti automaticamente al regexp, motivo per cui ho trascurato di aggiungerli, grazie. E no, le espressioni regolari non sono così semplici, possono diventare piuttosto complesse, anche se non quanto richiedono sottogruppi. – Tonio

risposta

6

È Matcher.hitEnd() che cosa stai cercando?

Pattern thePattern = Pattern.compile(theRegexString); 
Matcher m = thePattern.matcher(theStringToTest); 
if (m.matches()) { 
    return true; 
} 
return m.hitEnd(); 
+0

Bello! Funziona quasi. Certamente funziona come una sostituzione di ciò che sto facendo attualmente. Non funzionerà ancora per le corrispondenze parziali di coda (per esempio, "b3c" è una corrispondenza di coda parziale per 'ab [0-9] c'), ma la mia attuale soluzione non gestisce neanche quelle. – Tonio

+0

È vero che 'hitEnd()' ha lo stesso scopo della soluzione dell'OP di interrompere la regex in successivi gruppi opzionali. Ma non c'è ancora modo di rilevare una corrispondenza parziale che non si allinea con l'inizio della regex. –

4

Anche se ci possono essere alcuni trucchi disponibili, il tuo modo è probabilmente il migliore semanticamente. Descrive accuratamente ciò che stai cercando.

Tuttavia, il problema più grande è se è davvero necessario convalidare ogni volta che un carattere viene digitato nella casella di testo. Perché non puoi semplicemente convalidarlo una volta alla fine e risparmiarti qualche mal di testa?

+0

"Why", infatti ... :(Perché il client (tm) lo decreta così. Il problema con il modo in cui lo sto facendo, a parte il fatto che è abbastanza ostile (dovrei spiegare agli utenti dell'API sulle strane espressioni regolari parzialmente corrispondenti, ecc.), è che non corrisponderà alle stringhe che corrispondono alla FINE della regex. Nell'esempio sopra, non corrisponderà a "3c", che dovrebbe essere valido, dal momento che puoi sempre tornare indietro e aggiungere "ab" all'inizio. – Tonio

+0

Il client ha davvero specificato che doveva essere eseguito da un'espressione regolare? O è quella parte particolare del design che viene dal lato tecnico? – Yishai

+0

Il cliente non ha specificato che doveva essere eseguito da un'espressione regolare, questa era la nostra decisione progettuale. Inizialmente era fatto con una semplice corrispondenza delle stringhe, ma alla fine abbiamo deciso di usare le espressioni regolari perché alcuni schemi potevano essere piuttosto complessi. – Tonio

2

Ecco un'espressione regolare che può risolvere il vostro esempio particolare:

^(?:a|b|[0-9]|c|ab|b[0-9]|[0-9]c|ab[0-9]|b[0-9]c|ab[0-9]c)?$ 

In generale, se si può rompere l'espressione regolare in parti atomiche, che si può o insieme tutti i possibili raggruppamenti di loro, ma è grande e brutto. In questo caso, c'erano 4 parti (a, b, [0-9] e c), quindi dovevi OR insieme a 4 + 3 + 2 + 1 = 10 possibilità. (Per le parti n, è (n × (n +1))/2 possibilità). Potresti essere in grado di generare questo algoritmo, ma sarebbe un enorme dolore da testare. E qualsiasi cosa complessa (come un sottogruppo) sarebbe molto difficile da ottenere.

Una soluzione migliore è probabilmente solo per avere un messaggio accanto al campo di immissione che dice all'utente "informazioni insufficienti" o qualcosa del genere, e quando hanno ragione cambiarlo in una casella di controllo verde o qualcosa del genere. Ecco un recente articolo di A List Apart che pesa i pro ei contro dei diversi approcci a questo problema: Inline Validation in Web Forms.

+0

Questo è esattamente quello che sto cercando di evitare ... gergo sgraziato (OR nell'esempio, contenente sottogruppi opzionali alla fine nel mio esempio). :( Sfortunatamente, la soluzione migliore proposta è inaccettabile per il cliente: ciò che richiedono è il blocco dell'inserimento di testo di caratteri illegali (caratteri di significato non validi che non portano a una stringa valida) e feedback visivo di una stringa completamente valida (significato, come implementato, lo sfondo della casella di testo cambia colore quando la stringa corrisponde interamente alla regex. – Tonio

+0

Beh, potresti avere due passaggi? uno che esegue solo ab [0-9] c' e indica se la stringa completa è valido, e uno che esegue la regex grande per dire se quello che hanno inserito * potrebbe * essere valido. Puoi eseguire la regex grande su evento keyPressed, e se fallisce, si restituisce false (cioè non lasciare che l'utente entri quel carattere) – Kip

+0

Se potessi generare queste espressioni regolari algoritmicamente, sarebbe una soluzione valida. Generarle per semplici espressioni regolari non dovrebbe essere un problema, ma sfortunatamente non tutte i gexps usati sono semplici. – Tonio