2009-05-11 5 views
5

Muszę zastąpić wszystkie & w ciągu, który nie jest częścią encji HTML. Tak, że ciąg "This & udziałów w jednostkach > & <" zwróci "To & udziałów w jednostkach > & <"Optymalizacja regeksu - wymykanie się znakom ampersands w języku Java

A ja wymyśliłem ten regex-wzorca: "& [a-zA-Z0-9] {2 , 7}; "który działa dobrze. Ale nie jestem bardzo wyszkolony w regex, a kiedy testuję szybkość ponad 100k iteracji, to wykorzystuje on podwójną ilość czasu względem poprzedniej używanej metody, która nie używała regex. (Ale też nie działa w 100%).

Testcode:

long time = System.currentTimeMillis(); 
String reg = "&(?!&#?[a-zA-Z0-9]{2,7};)"; 
String s="a regex test 1 & 2 1&2 and &_gt; - &_lt;" 
for (int i = 0; i < 100000; i++) {test=s.replaceAll(reg, "&amp;");} 
System.out.println("Finished in:" + (System.currentTimeMillis() - time) + " milliseconds"); 

Więc pytanie byłoby, czy istnieją pewne oczywiste sposoby zoptymalizować ten regex wyrażenie na to, aby być bardziej skuteczne?

+0

musiałem napisać udziałów w jednostkach z podkreśleniem jak &_gt; albo że to pokazać jako symbol kod był za. – Duveit

+0

Prawie czterech z nas próbowało edytować tekst, aby otoczyć ampersandy cytatami w formacie kodu. Wystarczy wybrać odpowiedni tekst i użyć kodu, zachowa on znak ampersand. – cgp

Odpowiedz

6

s.replaceAll(reg, "&amp;") kompiluje wyrażenie regularne za każdym razem. Kompilacja wzoru raz zapewni pewien wzrost wydajności (~ 30% w tym przypadku).

long time = System.currentTimeMillis(); 
String reg = "&(?!&#?[a-zA-Z0-9]{2,7};)"; 
Pattern p = Pattern.compile(reg); 
String s="a regex test 1 & 2 1&2 and &_gt; - &_lt;"; 
for (int i = 0; i < 100000; i++) { 
    String test = p.matcher(s).replaceAll("&amp;"); 
} 
System.out.println("Finished in:" + 
      (System.currentTimeMillis() - time) + " milliseconds"); 
+0

To prawda, dostał go z 550ms na 450ms. Zobaczę, czy możemy zaimplementować prekompilowany wzór. – Duveit

0

Nie jestem zaznajomiony z klasami wyrażeń regularnych Java, ale ogólnie rzecz biorąc, możesz chcieć zbadać zerową szerokość wyprzedzenia; po ampersandzie.

Here is a link opisujące pozytywne i negatywne lookaheads

+0

To jest strona, na którą patrzyłem, gdy robiłem to w rzeczywistości :), przyjrzałem się pozytywnym lub negatywnym uprzedzeniom, ale zmiany, które próbowałem, nie zwiększyły wydajności. – Duveit

1

Innym sposobem na osiągnięcie tego wihtout dmuchanie głowę z regexp byłoby użyć StringEscapeUtils z Commons Lang.

+0

Używamy części tej biblioteki, jednak w tym przypadku musimy tylko naprawić ampersandy. I musi zaakceptować ciąg znaków, który może być mieszanką jednostek i prostych & s. - W każdym razie dzięki. – Duveit

2

Musisz wykluczyć & ze swojego stwierdzenia z wyprzedzeniem. Więc spróbuj tego wyrażenia regularnego:

&(?!#?[a-zA-Z0-9]{2,7};) 

Albo dokładniej:

&(?!(?:#(?:[xX][0-9a-fA-F]|[0-9]+)|[a-zA-Z]+);)