Rozwiązania
Najtrywialniejszym sposobem na poprawne rozbicie wg kilku separatorów byłoby wywołanie ponownie explode() dla każdego elementu wynikającego z pierwszego użycia tej funkcji, jednak ten sposób aż bije po oczach swym prostactwem więc nawet nie będę bawił się w jego poprawną implementację, a użyję jedynie takiego (dużego i nierealizującego zadania) przybliżenia:for ($i = 0; $i < 100000; $i++) { $temp = explode ( "/" , $string); foreach($temp as $elem) { $e = explode("?", $elem); $e = explode("&", $elem); } }
Kolejnym pomysłem jest iteracyjne podejście - używanie na przemian explode() i implode() w celu stworzenia pojedynczej tablicy z wynikiem.
for ($i = 0; $i < 100000; $i++) { $temp = explode ( "/" , $string); $temp = explode("&", implode("&", $temp)); $temp = explode("?", implode("?", $temp)); }
Skoro już postanowiliśmy iść w stronę podmian to warto by również rozważyć wielokrotne użycie str_replace().
for ($i = 0; $i < 100000; $i++) { $temp = str_replace("&", "/", $string); $temp = str_replace("?", "/", $temp); $temp = explode ( "/" , $temp); }
Nim przejdziemy do wyrażeń regularnych przytoczę tu jeszcze jeden przykład, który niestety działa jedynie w przypadku separatorów będących pojedynczymi znakami. Co ciekawe mimo, iż wykorzystanie funkcji strtok() wydaje się być potwornie nieefektywne to wyniki zbliżone są do naprzemiennego wywoływania funkcji explode() i implode().
for ($i = 0; $i < 100000; $i++) { $tok = strtok($string, "/&?"); $temp = array(); while ($tok !== false) { $temp[] = $tok; $tok = strtok("/&?"); } unset($tok); strtok('', ''); }
Ale czy mamy ograniczać się jedynie do takich kombinowanych sposobów? Może jest jedna "magiczna" funkcja, która zrobi to o czym myślimy? Ano jest i wykorzystuje magię wyrażeń regularnych, a zwie się ona preg_split().
for ($i = 0; $i < 100000; $i++) { $temp = preg_split("/[\/&?]/",$string); }
Tutaj jednak warto zwrócić uwagę na fakt, że jeśli naszym separatorem jest znak wielobajtowy to funkcja ta będzie generować dodatkowe puste elementy w wynikowej tablicy (jeden dodatkowy element na każde wystąpienie separatora). Sytuacja ta nie ma jednak miejsca jeśli separatorem nie jest znak a ciąg znaków, nawet jeśli wszystkie zawarte w nim elementy są znakami wielobajtowymi.
Tak czy inaczej remedium na ten problem jest funkcja mb_split():
for ($i = 0; $i < 100000; $i++) { $temp = mb_split("[\/&?]",$string); }
Ostatnim przytoczonym tu przykładem będzie połączenie wyrażeń regularnych wykorzystanych w funkcji preg_replace() wraz z pojedynczym wywołaniem explode():
for ($i = 0; $i < 100000; $i++) { $temp = preg_replace("/[&?]/","/",$string); $temp = explode("/", $temp); }
Testy wydajności
Jak widać istnieje wiele możliwości wykonania zadania dzielenia ciągu z użyciem wielu równorzędnych separatorów, ale które rozwiązanie jest najefektywniejsze? Popatrzmy na wyniki:single explode: 0.1573359966 multiple explode: 1.0633759499 explode & implode: 0.7556319237 replace & explode: 0.4618999958 strtok: 0.6737470627 preg_split: 0.9344220161 mb_split: 1.1594960690 preg_replace & explode: 1.1028780937
Dla separatorów składających się również z kilku znaków otrzymujemy takie wyniki:
single explode: 0.1560928822 multiple explode: 1.3294098377 explode & implode: 1.1651928425 replace & explode: 1.0913951397 preg_split: 1.8065340519 mb_split: 4.9289889336 preg_replace & explode: 1.8077979088
Jak widać wszystkie czasy wzrosły, przy czym wzrost mb_split() wynika w dużej mierze z używania wielobajtowych znaków.
Jeśli jednak zostaniemy przy tych trzech jedno-znakowych separatorach, a jedynie zwiększymy rozmiar badanego ciągu otrzymamy takie oto wyniki (10x mniej iteracji pętli testujących):
single explode: 0.2046608925 multiple explode: 1.8381199837 explode & implode: 1.0454828739 replace & explode: 0.5224039555 strtok: 1.0597200394 preg_split: 1.8259940147 mb_split: 2.1428530216 preg_replace & explode: 1.8069810867
Jeśli dodatkowo zamiast trzech separatorów użyjemy 5 będziemy mieć takie oto wyniki:
single explode: 0.2125821114 multiple explode: 4.1121268272 explode & implode: 3.3804459572 replace & explode: 1.6378400326 strtok: 3.4061551094 preg_split: 2.7953231335 mb_split: 6.4811940193 preg_replace & explode: 3.0788750648
Wnioski
Jak widać wydajność metod różni się w zależności tak od długości badanych ciągów, jak i ilości oraz postaci separatorów. Porównując wyniki możemy jednak dojść do wniosku, że najlepszym rozwiązaniem jest użycie duetu str_replace() wraz z explode(), który to we wszystkich testach okazał się najszybszym rozwiązaniem. Pozostałe metody są w zasadzie porównywalne, choć stosunek ich wydajności różni się w zależności od parametrów zadania (długość ciągu i postać separatorów). Pomimo to możemy jasno stwierdzić, że wielokrotne używanie explode() (multiple explode) jest całkowicie nieefektywne w porównaniu do pozostałych metod (zwłaszcza, że nie zaimplementowano tej funkcji w całości). Podobnie sytuacja wygląda w przypadku mb_split(), którą używać należałoby jedynie w przypadku skomplikowanych podziałów, a nie prostego dzielenia wg podanych słów.Wykorzystany kod do testowania można pobrać z mojego chomika (link).
Brak komentarzy:
Prześlij komentarz