Czy liczba jest liczbą? (PHP)

Nie dawno chciałem się dowiedzieć, jak najlepiej jest sprawdzać, czy tekst jest liczbą w Javie. Szybko trafiłem na ten oto wpis, którego autor sprawdził dostępne metody pod względem szybkości wykonywania. Wyszło, że najlepiej jest chałupniczo – przejrzeć znaki w stringu po kolei.

Zamieszczony wyżej link grzebie koncepcje używania wyrażeń regularnych do prostych celów w Javie. Zalecano mi ją w jednej z moich poprzednich notek, choć nawet wtedy całość nie wydawał mi się dobrym pomysłem (nie tylko mi).

Jak jednak wyrażenia regularne radzą sobie w językach skryptowych? Na warsztacie dzisiaj PHP.

Test jest prosty, kod zamieszczam poniżej. Poniżej przykładowe wyniki. Jak widać, nie ma w tym wielkiej filozofii, najlepiej sprawują się metody predefiniowane do wykrywania liczby w stringu. Wyrażenia regularne (zarówno preg_match jak i eregi) są gorsze. Najgorzej radzi sobie moja własnoręcznie napisana funkcja.

ctype_digit = 5.85733890533
is_numeric = 6.05098295212
preg_match = 8.32741999626
isNumber = 10.1650650501
eregi = 9.09768795967

Wnioski: jeśli można, używamy funkcji wbudowanych! Ale odkrycie. A wyrażanie regularne itp. zostawiamy na złożone zadania. Nie ma więc sensu wpychać ich wszędzie gdzie się da. Najgorzej jest wyłamywać otwarte drzwi – czyli klepać od początku takie funkcje których implementacje już istnieją.

Może ktoś, albo ja w wolnym czasie zajrzę jak sobie radzi z tym Python (i jego kompilowane wzorce). Można też sprawdzać jak radzą sobie funkcje wykrywające liczby z przecinkiem, albo heksadecymalne.

A i jeszcze jedno – w niektórych próbach eregi miało wyniki słabsze od preg_match, choć rzadziej.

Na koniec kod (choć nie jest zbyt odkrywczy).

<?php
$amount = 999999;
$strings = array();

for($i = 0; $i < $amount; $i++) {
        $strings[] = (string)(rand(111111,999999) * (rand(0,1)) ? -1 : 1);
}

$start = microtime(get_as_float);
for($i = 0; $i < $amount; $i++) {
        ctype_digit($string[i]);
}
echo 'ctype_digit = '.(microtime(get_as_float) - $start) ."\n";

$start = microtime(get_as_float);
for($i = 0; $i < $amount; $i++) {
        is_numeric($string[i]);
}
echo 'is_numeric = '.(microtime(get_as_float) - $start) ."\n";

$start = microtime(get_as_float);
for($i = 0; $i < $amount; $i++) {
        preg_match('!^[-+]?[0-9]+$!', $string[i]);
}
echo 'preg_match = '.(microtime(get_as_float) - $start) ."\n";

function isNumber($string)
{
        if (($string[0] !== '-') && ($string[0] !== '+') && ($string[0]  9))
                return false;

        for($i = 1; $i < strlen($string); $i++)
                if ($string[$i]  9)
                        return false;
        return true;
}

$start = microtime(get_as_float);
for($i = 0; $i < $amount; $i++) {
        isNumber($string[i]);
}
echo 'isNumber = '.(microtime(get_as_float) - $start) ."\n";

$start = microtime(get_as_float);
for($i = 0; $i 

PS. zżera sporo pamięci.

8 thoughts on “Czy liczba jest liczbą? (PHP)

  1. Twój isNumber wywali się na ułamkach. Albo dodaj mu możliwość łapania kropek, albo zamień go na isInt 😉

    Tak, wiem, czepiam się, ale za to mi płacą 😛

    Like

  2. Nie przeczytałeś dokładnie. Wszystkie te funkcje operują na całkowitych, ujemnych lub dodatnich. Widać to też zresztą w kodzie.

    Like

  3. Jak mi wskażesz formularz, który przepuści Ci numer telefonu 1e+77793433, to … też nie zmienię nic:P Nie o to tu chodziło – ale może w przyszłych notkach:)

    Like

Comments are closed.