2010-06-27 17 views
6

Sto cercando di utilizzare le espressioni regolari per determinare quale formato l'utente ha applicato quando si immette l'input in una casella di testo.
Le espressioni regolari sono i seguenti:Perché queste espressioni regolari vengono eseguite lentamente in Java?

(\\s?[" + alphabet + "]{9,9})+ 

Per determinare se l'input è una o più stringhe di lunghezza 9 in un dato alfabeto, eventualmente separati da spazi.

(>[\\w\\s]+\\n[" + alphabet + "\\s]+)+ 

Per verificare se l'ingresso è in FASTA format

Le espressioni regolari corrono terribilmente lento in caso di corrispondenza con . Perchè è questo?

Ho immaginato che ciò potrebbe essere dovuto a Java che memorizza tutte le potenziali corrispondenze (che non ho bisogno a questo punto), ma l'aggiunta di ?: in ogni parentesi spezza la regex. Come dovrebbe essere fatto?

Grazie,

Martin

Edit 1: non sono riuscito a riprodurre il problema - succede solo su un computer. Questo potrebbe suggerire qualcosa di sbagliato in quella particolare configurazione VM.
Abbiamo bisogno di qualcosa di più robusto, e quindi lo implementeremo in modo diverso. Ho scelto la risposta di Joel come quella giusta, dal momento che credo che alcuni casi speciali in Pattern potrebbero essere la causa.

+0

Quanti pattern si sta tentando potenzialmente di confrontare con ciascuna stringa di input? I modelli sono dinamici o statici? –

+0

@Joel Esistono solo questi due modelli. Sono statici. L'uso di String.matches causerà ogni volta una compilazione, ma anche una corrispondenza con i pattern una sola volta richiede molto tempo (> 10 secondi per circa 300 caratteri immessi) –

+0

puoi definire "terribilmente lento"? –

risposta

0

Se si dispone di un numero di modelli di espressioni regolari diversi confrontati con lo stesso input per provare a classificare l'input, è probabile che si stia utilizzando un generatore di analizzatore lessicale come JFlex.

Altri strumenti di analisi lessicale basati su Java e strumenti di analisi utilizzati in genere nella compilazione del compilatore sono elencati here.

+0

Questi sono strumenti utili, grazie! Ma ho solo 2 regex, e questo dovrebbe essere molto semplice - penso che l'uso di JFlex e simili sarebbe eccessivo. –

+0

@Martin - Suona come JFlex o simili sarebbe più che normalmente necessario in questo caso. Tuttavia, osservando più da vicino le espressioni regolari che stai usando, è possibile che il tuo caso stia mostrando qualche caso degenerato in come la classe Pattern compila il suo analizzatore. Può valere la pena provare JFlex solo per vedere se può produrre un analizzatore più stretto per questo scenario. –

1

string.matches() compilare la regex ogni volta che lo si fa. Invece, guarda le classi Pattern/Matcher, che ti permettono di memorizzare le regex precompilate.

Un'altra cosa è utilizzare i gruppi di espressioni regolari non acquisibili se non è necessario il risultato della corrispondenza.

+0

Ho chiamato solo le corrispondenze() una volta, quindi non dovrebbe essere un problema. Le regex funzionano bene con piccoli input, ma orrendamente lentamente con l'input di più, diciamo, di 200 caratteri. Non sono riuscito a far funzionare i gruppi non-catturanti: puoi fare un esempio? –

+0

Passare a gruppi non a cattura non ti darà un fattore di 1000 miglioramenti. Ancora, questo è come lo si fa - mettere?: Dopo la parentesi di apertura - esempio: (?: \\ s? ["+ Alfabeto +"] {9,9}) + – ddimitrov

1

questo potrebbe non spiegare il tuo particolare problema. ma una volta mi sono tuffato nell'implementazione regex di JDK, e sono rimasto sorpreso dal fatto che lo non sofisticato sia lo. in realtà non costruisce una macchina a stati che avanza a ogni input char. Presumo che abbiano le loro ragioni.

nel tuo caso, è così facile da scrivere un parsing da solo, a mano. la gente ha paura di farlo, sembra "stupido" codificare manualmente questi piccoli passaggi, e la gente pensa che le biblioteche affermate debbano fare degli splendidi trucchi per sovraperformare le soluzioni nazionali. non è vero. in molti casi, i nostri bisogni sono piuttosto semplici, ed è più semplice e veloce per il fai-da-te.

+0

Il metodo Pattern.compile() crea una macchina a stati dei discendenti della classe Pattern.Node. Vuoi dire che costruisce un automa NFA in contrapposizione a DFA? Questo è il design utilizzato dalla maggior parte dei motori regex ricchi di funzionalità, la velocità di trading per le funzionalità. Ecco un articolo che spiega questo e suggerisce un'alternativa: http://weblogs.java.net/blog/2006/03/27/faster-java-regex-package – ddimitrov