2013-03-05 11 views
5

Próbuję poprawić wydajność niektórych kodu. Wygląda to mniej więcej tak:Jak ustalić, czy ciąg nie jest wyrażeniem regularnym?

public boolean isImportant(String token) { 
    for (Pattern pattern : patterns) { 
     return pattern.matches(token).find(); 
    } 
} 

Co zauważyłem jest to, że wiele wzorców wydają się być proste literały łańcuchowe bez regularnych konstruktów ekspresyjnych. Tak, chcę po prostu zapisać je w oddzielnej liście (importantList) i zrobić test równości zamiast przeprowadzania droższej wzór mecz, takich jak następuje:

public boolean isImportant(String token) { 
    if (importantList.contains(token)) return true; 

    for (Pattern pattern : patterns) { 
     return pattern.matches(token).find(); 
    }   
} 

Jak programowo określić, czy dany ciąg nie zawiera konstrukcje regularnych wyrażeń?

Edytuj: Należy dodać, że odpowiedź nie musi być wrażliwa na wyniki. (tzn. można używać wyrażeń regularnych) Zajmuję się głównie wydajnością isImportant(), ponieważ jest to nazywane miliony razy, podczas gdy inicjacja wzorców jest wykonywana tylko raz.

+1

Nie robiłbyś regularnego wyrażenia na łańcuchu znaków, aby określić, czy jest to wyrażenie regularne za każdym razem znacznie gorsze niż użycie każdego ciągu jako wyrażenia regularnego? –

+3

@MikeM: Nie o to pyta. 'hello' jest doskonale prawidłowym wyrażeniem regularnym. –

+0

Niemożliwe (przynajmniej nie jest to łatwe lub wartościowe, chyba że znajdziesz wzór w zwykłych literałach ciągów znaków). Prosty łańcuch literowy jest prawidłowym wzorcem regex. – AC1

Odpowiedz

3

To będzie trudne. Możesz sprawdzić, czy nie ma żadnych metaznaków wyrażeń regularnych; to powinno być dobre przybliżenie:

Pattern regex = Pattern.compile("[$^()\\[\\]{}.*+?\\\\]"); 
Matcher regexMatcher = regex.matcher(subjectString); 
regexIsLikely = regexMatcher.find(); 

Czy warto, to kolejne pytanie. Czy na pewno dopasowanie do wyrażenia regularnego jest wolniejsze niż sprawdzanie listy (zwłaszcza, że ​​w wielu wypadkach, w wielu wypadkach, przeprowadzasz dopasowanie do wyrażenia regularnego)? Założę się, że jest to o wiele szybsze, aby zachować dopasowanie do regex.

+0

To jest rozwiązanie, z którym współpracowałem. Co ciekawe, skróciłem czas przetwarzania o około 50%. –

4

normalnie nienawidzę odpowiedź, że to powiedzieć, ale ...

nie rób tego.

Prawdopodobnie nie spowoduje, że kod będzie działał szybciej, w rzeczywistości może nawet spowodować, że program zajmie więcej czasu.

Jeśli naprawdę potrzebujesz zoptymalizować swój kod, prawdopodobnie istnieje dużo bardziej skutecznych miejsc, do których możesz się udać.

+0

Zamierzam, aby profiler odpowiedział na pytanie, czy optymalizacje mają sens. –

2

Nie ma sposobu, aby to ustalić, ponieważ każdy wzór regex to nic innego jak ciąg. Ponadto istnieje prawie żadna różnica wydajności jest silny jak regex dziś i jestem całkiem pewny, czy długości wzór i źródło są takie same, check equity jest pierwszą, która zostanie wykonana

+1

To zależy, ale oszacowałbym, że Java próbuje wykonać znacznie bardziej efektywne wyliczenie DFA najpierw i tylko zamienia się na NFA, jeśli wyrażenie to wymaga (np. Jeśli obejmuje obejście). –

1

Jest źle

for (Pattern pattern : patterns) 

powinieneś utworzyć jedno duże wyrażenie regularne, które ORs wszystkie wzory; następnie dla każdego wejścia pasujesz tylko raz.

+0

Dzięki. Tak naprawdę to zrobiłem i okazało się, że użycie jednego gigantycznego wzoru było o 1/3 szybsze niż dopasowanie do wielu małych wzorów. –

Powiązane problemy