2011-12-22 15 views
16

To powinno być dość proste pytanie, ale nie znalazłem nigdzie odpowiedzi. W jaki sposób można utworzyć wyrażenie regularne, które pasuje do 2 TYLKO 2 znaków lub co najmniej 4 znaków. Oto moja obecna metoda robi to (ignorować samego wyrażenia regularnego, to oprócz punktu):wyrażeń regularnych dla n znaków lub co najmniej m znaków

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

Jednak metoda ta zajmuje dwa razy więcej czasu (i wynosi około 0,3 s wolniej dla mnie na plik 400 linii) , więc zastanawiałem się, czy istnieje lepszy sposób na zrobienie tego?

Odpowiedz

14

Optymalizuj początek i zakotwicz go.

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

(Ponadto, powiedział ignorować samego wyrażenia regularnego, ale domyśliłem się, że prawdopodobnie chciał 0-9, nie 0_9)

EDIT Hm, byłem pewien, że czytałem, że chcesz dopasować linie. Usuń kotwice (^$), jeśli chcesz dopasować również do linii. Jeśli dopasujesz tylko pełne linie, kotwice przyspieszą (dobrze, przynajmniej kotwica z przodu ^).

+0

Działa to doskonale. I chcę tylko dopasować początek linii, więc po prostu zatrzymam ^. – david

3

Twoje rozwiązanie wygląda całkiem nieźle. Jako alternatywę można spróbować smth tak:

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

Btw, myślę, że chcesz myślnik zamiast podkreślenia między 0 i 9, prawda?

+0

Tak, chciałem użyć łącznika zamiast podkreślenia między 0 a 9. BTW, co oznacza "?:" W twoim regexie? – david

+0

@ david-'?:' Oznacza, że ​​wyrażenie w nawiasie nie jest przechwytywane. Sprawdź tę stronę, jeśli nie wiesz, co mam przez to rozumieć: http://www.regular-expressions.info/brackets.html – dlras2

+0

@david, to jest dla grupy niezapisującej, jak wspomniano powyżej i jest bardziej wydajna niż regularna Grupa. –

-1

więc w zasadzie chcesz dopasować słów o długości 2 lub 2 + 2 + N, N> = 0

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

przykład praca:

#!/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"; 
    } 
} 

plik wejściowy:

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

moc wyjściowa:

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, jako A) boli mnie, aby zobaczyć zduplikowane wyrażenia zamiast '{n} ', i B) twoje rozwiązanie wychwytuje tylko łańcuchy o równej długości (a nawet wtedy nie robi tego szczególnie sprawnie). – dlras2

+0

A) nie komentarz, B) masz sprytne oko, dziękuję za zauważenie błędu. – user237419

+0

Z ciekawości, dlaczego preferujesz powtarzanie siebie? – dlras2

1

Przedstawione rozwiązanie jest poprawne.

Jeśli próbujesz zoptymalizować procedurę, a liczba pasujących ciągów pasujących do co najmniej 2 znaków jest znacznie mniejsza niż tych, które nie są zgodne, rozważ zaakceptowanie wszystkich ciągów o długości 2 lub większej, a następnie ich odrzucenie, jeśli " re o długości 3. Może to zwiększyć wydajność, sprawdzając tylko wyrażenie regularne raz, a drugie wywołanie nie musi być nawet wyrażeniem regularnym; sprawdzanie długości ciągu jest zwykle niezwykle szybką operacją.

Naprawdę, naprawdę trzeba uruchomić testy na danych rzeczywistych, aby sprawdzić, czy zwiększy to prędkość.

+0

Dobra, dziękuję za cynk. Wypróbuję twoją metodę. To brzmi jak niezły pomysł. – david

Powiązane problemy