2011-12-22 14 views
16

Questa dovrebbe essere una domanda di regex piuttosto semplice ma non ho potuto trovare alcuna risposta da nessuna parte. Come si fa un'espressione regolare, che corrisponde a SOLO 2 caratteri o almeno a 4 caratteri. Ecco il mio attuale metodo di farlo (ignorare la regex in sé, che è oltre il punto):regex per n caratteri o almeno m caratteri

[A-Za-z0_9_]{2}|[A-Za-z0_9_]{4,} 

Tuttavia, questo metodo richiede il doppio del tempo (ed è di circa 0,3 secondi più lento per me su un file di 400 line) , quindi mi chiedevo se ci fosse un modo migliore per farlo?

risposta

14

Ottimizza l'inizio e ancorarlo.

^[A-Za-z0-9_]{2}(?:|[A-Za-z0-9_]{2,})$ 

(Inoltre, hai detto di ignorare l'espressione regolare in sé, ma ho indovinato che probabilmente voleva 0-9, non 0_9)

EDIT Hm, ero sicuro che ho letto che si vuole abbinare linee. Rimuovere gli ancoraggi (^$) se si desidera che corrispondano anche all'interno della linea. Se combaci solo con le linee complete, le ancore ti velocizzeranno (beh, l'ancoraggio anteriore ^ sarà, almeno).

+0

Funziona perfettamente. E voglio solo abbinare l'inizio di una riga, quindi terrò solo il ^. – david

3

La tua soluzione sembra abbastanza buona. In alternativa si può provare dovrebbe occupare così:

[A-Za-z0-9_]{2}(?:[A-Za-z0-9_]{2,})? 

Btw, Penso che si desidera trattino invece di sottolineatura tra 0 e 9, non è vero?

+0

Sì, intendevo usare un trattino invece di un trattino basso tra 0 e 9. BTW, cosa significa "?:" Nella tua espressione regolare? – david

+0

@ david-'?:' Indica che l'espressione tra parentesi non viene acquisita. Controlla questo sito se non sai cosa intendo con questo: http://www.regular-expressions.info/brackets.html – dlras2

+0

@david, è per i gruppi che non catturano come detto sopra ed è più efficiente che regolare gruppo. –

-1

in modo sostanzialmente si desidera far corrispondere le parole di lunghezza 2 o 2 + 2 + N, N> = 0

([A-Za-z0-9][A-Za-z0-9](?:[A-Za-z0-9][A0Za-z0-9])*) 

esempio funzionante:

#!/usr/bin/perl 

while (<STDIN>) 
{ 
    chomp; 
    my @matches = ($_=~/([A-Za-z0-9][A-Za-z0-9](?:[A-Za-z0-9][A0Za-z0-9])*)/g); 
    for my $m (@matches) { 
     print "match: $m\n"; 
    } 
} 

file di input:

cat in.txt 
ab abc bcad a as asdfa 
aboioioi i i abc bcad a as asdfa 

produzione:

perl t.pl <in.txt 
match: ab 
match: ab 
match: bcad 
match: as 
match: asdf 
match: aboioioi 
match: ab 
match: bcad 
match: as 
match: asdf 
+1

-1, come A) mi dispiace vedere le espressioni duplicate invece di '{n}', e B) la tua soluzione cattura solo stringhe di lunghezza pari (e anche allora non lo fa in modo particolarmente efficiente.) – dlras2

+0

A) no commento, B) hai un occhio acuto, grazie per aver notato l'errore. – user237419

+0

Per curiosità, perché la preferenza per ripetersi? – dlras2

1

La soluzione che si presenta è corretta.

Se stai cercando di ottimizzare la routine, e il numero di partite stringhe corrispondenti 2 o più caratteri è molto più piccolo rispetto a quelli che non lo fanno, in considerazione di accettare tutte le stringhe di lunghezza 2 o superiore, poi gettando quelli se' re della lunghezza 3. Ciò può aumentare le prestazioni controllando una volta la regex e la seconda chiamata non deve nemmeno essere un'espressione regolare; il controllo di una lunghezza di stringa è in genere un'operazione estremamente rapida.

Come sempre, è davvero necessario eseguire test sui dati del mondo reale per verificare se questo potrebbe aumentare la velocità.

+0

OK, grazie per il suggerimento. Proverò il tuo metodo. Sembra una buona idea. – david

Problemi correlati