За последние 24 часа нас посетил 17381 программист и 1298 роботов. Сейчас ищут 1660 программистов ...

Любителям регулярных выражений

Тема в разделе "Регулярные выражения", создана пользователем Юрий Удовиченко, 16 окт 2011.

  1. Юрий Удовиченко

    Юрий Удовиченко Активный пользователь

    С нами с:
    26 сен 2011
    Сообщения:
    25
    Симпатии:
    0
    Адрес:
    Хабаровск
    Пытаясь узнать, каких "колёс" я наизобретал - решил сравнить метод поиска любой цифры перед заданным словом через функцию, написанный мной с тем же методом, но с помощью регулярного выражения.
    Какова же была моя радость, когда я увидел, что мой способ работает в большинстве случаем быстрее - особенно когда позиция искомой величины находится далее примерно 50 символов в строке.
    Привожу только тестовые результаты. Если надо - могу привести исходник функции.
    Общий смысл - найти необходимую цифру (если есть) перед заданным словом - с любым количеством пробелов, с десятичным знаком (.||,) или без.
    Тест:
    PHP:
    1.  
    2. function correct_time() {
    3.     $time=microtime();
    4.     $exp=explode(' ',$time);
    5.     (float) $result=$exp[0]+$exp[1];
    6.     return $result;
    7.     }
    8.  
    9. $cicles=10000; // Количество циклов
    10. // Изначальный текст
    11. $text='Продаётся дом 45,7 кв м. В 150 метрах от остановки. Не агентство. 2 этажн.Возможен торг. 8,5 миллионов  тел 576-2342-23.';
    12. // Выражение поиска
    13. $posix="/(\d+(,?|.?)\d*)\s*(млн|миллионов|милионов)/";
    14.  
    15. $start=correct_time(); // Вычисление времени (преобразование в формат x.yy, где x - секунды и yy - доли секунд)
    16. for ($i=0; $i<=$cicles; $i++) preg_match($posix, $text, $result);
    17. $end=correct_time(); // Вычисление времени
    18.  
    19. echo '<br>Функция preg_match = '.($end-$start).' секунд. Результат поиска = '.$result[1].'<br>';
    20.  
    21. $start=correct_time(); // Вычисление времени
    22. for ($i=0; $i<=$cicles; $i++) { // Алтернатива поиска - аналог posix- выражения
    23.     $res=find_digit_at_word($text,'млн'); // Поиск. Функция возвращает цифру перед заданным словом. Если не найдено = false;
    24.     if ($res==false) $res=find_digit_at_word($text,'миллионов'); // Если не найдено первое слово
    25.     if ($res==false) $res=find_digit_at_word($text,'милионов'); // Если не найдено второе слово
    26.     }
    27. $end=correct_time();  // Вычисление времени
    28.  
    29. echo '<br>Новая функция        = '.($end-$start).' секунд. Результат поиска= '.$res;
    30.  
    Выдаёт:

    Функция preg_match = 0.760666131973 секунд. Результат поиска = 8,5

    Новая функция = 0.567981004715 секунд. Результат поиска= 8.5

    P.S. У меня как раз много циклов, и это замедляет значительно.
    P.S.2 Если строки заведомо малы - то лучше использовать регулярку.
    P.S.3 - Если надо - выложу код функции, может ещё можно подправить.
    P.S.4 Чёт у меня тут подсветка не работает
     
  2. Михаил

    Михаил Активный пользователь

    С нами с:
    12 июл 2009
    Сообщения:
    545
    Симпатии:
    0
    Адрес:
    Bielarus
    А зачем здесь цикл?
    Код (Text):
    1.  for ($i=0; $i<=$cicles; $i++) preg_match($posix, $text, $result);
    есть же preg_match_all
    Из-за этого цикла и работает так медленно регулярное выражение. В целом мне кажется что с *_all будет быстрее, чем с вашей функцией.
     
  3. Юрий Удовиченко

    Юрий Удовиченко Активный пользователь

    С нами с:
    26 сен 2011
    Сообщения:
    25
    Симпатии:
    0
    Адрес:
    Хабаровск
    Цикл - это только для того, чтобы это задание повторилось 10 тысяч раз. - чтобы было легче сравнивать время. Можешь поставить один цикл. или вообще без него - но тогда его выполнение займёт 0,00000001 секунды - ты не поймёшь, сколько реально ушло времени.
    А функции в обоих случаях ищут только по одному совпадению .В принципе перестроить на поиск всех - не сложно. и сравнить с preg_match_all
     
  4. Михаил

    Михаил Активный пользователь

    С нами с:
    12 июл 2009
    Сообщения:
    545
    Симпатии:
    0
    Адрес:
    Bielarus
  5. kmichael

    kmichael Активный пользователь

    С нами с:
    20 сен 2011
    Сообщения:
    19
    Симпатии:
    0
    Адрес:
    Новосибирск
    ваше выражение можно оптимизировать таким образом
    Код (Text):
    1.  
    2. $posix="/(\d+(?:,|.)?\d?)\s*(?:млн|миллионов|милионов)/";
    я бы предложил такой вариант, который еще быстрее:
    Код (Text):
    1.  
    2. $posix="/([,.0-9]+)\s*(?:млн|миллионов|милионов)/";
    но у данных выражений есть недостаток, они допускают неправильные совпадения:
    попробуйте применить их к строке
    Код (Text):
    1.  
    2. $text='Продаётся дом 45,7 кв м. В 150 метрах от остановки. Не агентство. 2 этажн.Возможен торг. 8,5.9,4 миллионов  тел 576-2342-23.';
    мой вариант еще допускает совпадения в подобных строках
    Код (Text):
    1.  
    2. $text='Продаётся дом 45,7 кв м. В 150 метрах от остановки. Не агентство. 2 этажн.Возможен торг.    миллионов  тел 576-2342-23.';
    для решения, которое будет исключать неправильные совпадения, необходимо проанализировать входные данные, возможно этих шаблонов вполне достаточно
     
  6. Юрий Удовиченко

    Юрий Удовиченко Активный пользователь

    С нами с:
    26 сен 2011
    Сообщения:
    25
    Симпатии:
    0
    Адрес:
    Хабаровск
    Хорошо. Попробую. Пока занимаюсь прочими работами, т.к. и эта функция работает сносно, а работы валом. Вот когда дойдёт речь дело ускорений и оптимизации - буду пробовать всё :)