strpos vs preg_match — различия в памяти и ресурсах

Были вопросы о том, что быстрее strpos или preg_match, но мне интересно узнать, что использует меньше всего ресурсов памяти и процессора.

Я хочу проверить строку на одно из 5 совпадений:

if (strpos($key, 'matchA') !== false || strpos($key, 'matchB') !== false || strpos($key, 'matchC') !== false || strpos($key, 'matchD') !== false || strpos($key, 'matchE') !== false) 

if (preg_match("~(matchA|matchB|matchC|matchD|matchE)~i",$key, $match))

Как лучше всего это сделать с наименьшей нагрузкой на сервер?


person Tom    schedule 01.07.2016    source источник
comment
Этот вопрос лучше подходит для форума по обзору кода. codereview.stackexchange.com   -  person Jeet    schedule 01.07.2016
comment
Хорошо, спасибо - я опубликую это там. Спасибо   -  person Tom    schedule 01.07.2016
comment
Я думаю, что этот вопрос актуален и для SO.   -  person Eiko    schedule 01.07.2016


Ответы (2)


В статье Джеффри Фридла «Освоение регулярных выражений» говорится, что использование встроенных функций, не связанных с регулярными выражениями, таких как strpos() и str_match(), всегда лучше и быстрее, чем использование preg_match() (при условии, что вы используете набор preg), учитывая, что ваш текст совпадения не является шаблоном< /сильный>.

person Mav    schedule 01.07.2016

Мне было любопытно, поэтому я написал следующий короткий скрипт:

<?php

$keys = [
    "veryshort",
    "veryvertlongstringhereveryvertlongstringhereveryvertlongstringhereveryvertlongstringhereveryvertlongstringhereveryvertlongstringhere",
    "shortstringwithmatchBintheresomewhere",
    uniqid("",true).uniqid("",true).uniqid("",true).uniqid("",true).uniqid("",true).uniqid("",true).uniqid("",true).uniqid("",true).uniqid("",true) //just random stuff 
];
$ops = 1000000;

foreach ($keys as $key) {
    $mt = microtime(true);


    for ($i = 0;$i < $ops;$i++) {
        $bool = strpos($key, 'matchA') !== false || strpos($key, 'matchB') !== false || strpos($key, 'matchC') !== false || strpos($key, 'matchD') !== false || strpos($key, 'matchE') !== false;
    }

    $mtEnd = microtime(true);
    echo PHP_EOL."String $key".PHP_EOL;
    echo "StrPos".PHP_EOL;
    echo "Total time: ".($mtEnd-$mt).PHP_EOL;
    echo "Average time: ".($mtEnd-$mt)/$ops.PHP_EOL;

    $mt = microtime(true);
    for ($i = 0;$i < $ops;$i++) {
        $bool = preg_match("~(matchA|matchB|matchC|matchD|matchE)~i",$key, $match);
    }
    $mtEnd = microtime(true);
    echo "preg_match".PHP_EOL;
    echo "Total time: ".($mtEnd-$mt).PHP_EOL;
    echo "Average time: ".($mtEnd-$mt)/$ops.PHP_EOL;

}

Это результат, который я получил.

String veryshort
StrPos
Total time: 0.4722261428833
Average time: 4.722261428833E-7
preg_match
Total time: 0.39836096763611
Average time: 3.9836096763611E-7

String veryvertlongstringhereveryvertlongstringhereveryvertlongstringhereveryvertlongstringhereveryvertlongstringhereveryvertlongstringhere
StrPos
Total time: 0.49143600463867
Average time: 4.9143600463867E-7
preg_match
Total time: 0.4594030380249
Average time: 4.594030380249E-7

String shortstringwithmatchBintheresomewhere
StrPos
Total time: 0.21032190322876
Average time: 2.1032190322876E-7
preg_match
Total time: 0.6224000453949
Average time: 6.224000453949E-7

String 577625b20d9632.50190056577625b20d9798.81879058577625b20d97e6.80533504577625b20d97f9.27988846577625b20d9806.94313293577625b20d9803.05317354577625b20d9818.68372474577625b20d9818.19126932577625b20d9825.80344644
StrPos
Total time: 0.50694704055786
Average time: 5.0694704055786E-7
preg_match
Total time: 0.4893159866333
Average time: 4.893159866333E-7

Моя интерпретация этого заключается в том, что запуск одного preg_match быстрее, чем запуск нескольких strpos из-за накладных расходов на вызовы функций и дополнительных сравнений для каждой функции, однако это не похоже на тот случай, когда в вашей строке есть совпадение, возможно, потому, что когда это происходит, когда базовый конечный автомат регулярных выражений меняет состояние и делает больше вещей (предположительно).

Я предполагаю, что ответ не так прост, как «A быстрее, чем B», а скорее «возьмите этот код, вставьте свои обычные варианты использования и посмотрите, что лучше для вашего конкретного случая».

person apokryfos    schedule 01.07.2016
comment
Спасибо за ваш ответ, это показывает затраченное время, а не используемые ресурсы. Есть ли способ увидеть это? - person Tom; 01.07.2016
comment
@Tom Я не знаю ничего, что могло бы рассказать вам о ресурсах, используемых конкретной функцией (есть php.net/manual/en/function.memory-get-peak-usage.php, но это, вероятно, не подходит для приведенного выше кода). Все, что я могу сказать, это то, что и preg_match, и strpos принимают аргументы по значению, что означает, что они сделают копию каждого переданного аргумента. Помимо этого, strpos не требует дополнительного места, но не уверен насчет preg_match, поэтому вам, вероятно, будет хуже, если вы используете 5 strpos вместо 1 preg_match с точки зрения ресурсов. - person apokryfos; 01.07.2016