2009-09-25 2 views
0

У меня есть массив строк, которые я хочу попробовать и сопоставлять до конца нормальной строки. Я не уверен, что это лучший способ сделать это на PHP.Поиск массива различных строк внутри одной строки в PHP

Это Сорта, что я пытаюсь сделать:

Пример:

Вход: ABCDE

Поиск массива: эр В.Р., де

Совпадение: де

Моя первая мысль заключалась в том, чтобы написать цикл, который проходит через t он массирует и создает регулярное выражение, добавляя «\ b» в конце каждой строки, а затем проверяем, найден ли он во входной строке. Хотя это будет работать, кажется, что это неэффективно, чтобы пропустить весь массив. Мне говорили, что регулярные выражения медленны в PHP и не хотят реализовывать что-то, что приведет меня к неправильному пути.

Есть ли лучший способ увидеть, существует ли одна из строк в моем массиве в конце строки ввода?

Функция preg_filter() выглядит так, как будто она может выполнять эту работу, но для PHP 5.3+, и я все еще придерживаюсь стабильности 5.2.11.

+0

'Поиск массива: er, wr, de' - они всегда имеют одинаковую длину или же это может быть что-то вроде' er, a, xyz'? Насколько «важна» эта оптимизация? Это действительно узкое место в вашем приложении? – VolkerK

+0

Элементы в массиве поиска различаются по размеру. Я ищу пару сотен. Результат кэшируется, но я все же хочу свести к минимуму работу. – 2009-09-25 20:12:58

ответ

5

Для чего-то такого простого вам не нужно регулярное выражение. Вы можете либо перебрать массив, и использовать strpos, чтобы увидеть, является ли индекс длиной (input) - length (test). Если каждая запись в массиве поиска всегда имеет постоянную длину, вы также можете ускорить процесс, отрубив конец ввода, а затем сравнив это с каждым элементом массива.

Вы не можете избежать прохождения всего массива, как в худшем общем случае, элемент, который соответствует, будет находиться в конце массива. Однако, если массив не огромен, я бы не стал слишком беспокоиться о производительности - он будет намного быстрее, чем вы думаете.

+0

Спасибо! Я знал, что, должно быть, был более простой способ. – 2009-09-25 20:11:37

1

Хотя компиляция регулярного выражения занимает какое-то время, я бы не отказался от использования pcre так легко. Если вы не найдете функцию сравнения, которая принимает несколько игл, вам нужен цикл для игл, и выполнение цикла + вызов функции сравнения для каждой отдельной иглы также требует времени.

Возьмем тестовый скрипт, который извлекает все имена функций из php.net и ищет определенные окончания. Это был только adhoc-скрипт, но я полагаю, что какая бы ни была функция strcmp-ish function +, которую вы используете, будет медленнее, чем простой шаблон pcre (в данном случае).

count($hs)=5549 
pcre: 4.377925157547 s 
substr_compare: 7.951938867569 s 
identical results: bool(true) 

Это был результат поиска девяти различных моделей. Если бы было только два («yadda», «ge»), оба метода принимали одно и то же время.

Не стесняйтесь критиковать тестовый скрипт (не всегда ошибки в синтетических тестах, которые очевидны для всех, но сам ;-)?)

<?php 
/* get the test data 
All the function names from php.net 
*/ 
$doc = new DOMDocument; 
$doc->loadhtmlfile('http://docs.php.net/quickref.php'); 
$xpath = new DOMXPath($doc); 
$hs = array(); 
foreach($xpath->query('//a') as $a) { 
    $hs[] = $a->textContent; 
} 
echo 'count($hs)=', count($hs), "\n"; 
// should find: 
// ge, e.g. imagick_adaptiveblurimage 
// ing, e.g. m_setblocking 
// name, e.g. basename 
// ions, e.g. assert_options 
$ns = array('yadda', 'ge', 'foo', 'ing', 'bar', 'name', 'abcd', 'ions', 'baz'); 
sleep(1); 

/* test 1: pcre */ 
$start = microtime(true); 
for($run=0; $run<100; $run++) { 
    $matchesA = array(); 
    $pattern = '/(?:' . join('|', $ns) . ')$/'; 
    foreach($hs as $haystack) { 
    if (preg_match($pattern, $haystack, $m)) { 
     @$matchesA[$m[0]]+= 1; 
    } 
    } 
} 
echo "pcre: ", microtime(true)-$start, " s\n"; 
flush(); 
sleep(1); 

/* test 2: loop + substr_compare */ 
$start = microtime(true); 
for($run=0; $run<100; $run++) { 
    $matchesB = array(); 
    foreach($hs as $haystack) { 
    $hlen = strlen($haystack); 
    foreach($ns as $needle) { 
     $nlen = strlen($needle); 
     if ($hlen >= $nlen && 0===substr_compare($haystack, $needle, -$nlen)) { 
     @$matchesB[$needle]+= 1; 
     } 
    } 
    } 
} 
echo "substr_compare: ", microtime(true)-$start, " s\n"; 
echo 'identical results: '; var_dump($matchesA===$matchesB); 
0

Я мог бы подойти к этому в обратном направлении;

если ваша строка заканчивается список фиксирована или изменяется редко, я хотел бы начать с предварительной обработкой его, чтобы сделать его легко подобрать против, затем захватить конец вашей строки и посмотреть, если он соответствует!

Пример кода:

<?php 

// Test whether string ends in predetermined list of suffixes 
// Input: string to test 
// Output: if matching suffix found, returns suffix as string, else boolean false 
function findMatch($str) { 
    $matchTo = array(
     2 => array('ge' => true, 'de' => true), 
     3 => array('foo' => true, 'bar' => true, 'baz' => true), 
     4 => array('abcd' => true, 'efgh' => true) 
    ); 

    foreach($matchTo as $length => $list) { 
     $end = substr($str, -$length); 

     if (isset($list[$end])) 
      return $end; 
    } 

    return $false; 
} 

?> 
0

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

Затем перейдите от конца строки ввода к одному символу в момент времени (e, de, cde и т. Д.) И вычислите хэш на подстроке на каждой итерации. Если хэш находится в вашем массиве поиска, у вас много.

Смежные вопросы