Как вы выполняете preg_match, где шаблон представляет собой массив, в php? - PullRequest
6 голосов
/ 26 марта 2009

У меня есть массив, полный шаблонов, которые мне нужны. Есть ли способ сделать это, кроме цикла for ()? Я пытаюсь сделать это с минимальной нагрузкой на процессор, так как я буду делать десятки таких каждую минуту.

Пример из реальной жизни: я создаю средство проверки состояния ссылок, которое будет проверять ссылки на различные онлайн-видео сайты, чтобы убедиться, что видео все еще живы. Каждый домен имеет несколько «мертвых» ключевых слов, если они найдены в html-странице, это означает, что файл был удален. Они хранятся в массиве. Мне нужно сопоставить содержимое массива с выводом html страницы.

Ответы [ 7 ]

20 голосов
/ 26 марта 2009

Прежде всего, если вы буквально делаете только дюжины каждые минуты , то я бы не стал сильно беспокоиться о производительности в этом случае. Эти совпадения довольно быстрые, и я не думаю, что у вас возникнут проблемы с производительностью, если вы будете выполнять итерацию по массиву шаблонов и вызывать preg_match отдельно, например так:

$matches = false;
foreach ($pattern_array as $pattern)
{
  if (preg_match($pattern, $page))
  {
    $matches = true;
  } 
}

Вы действительно можете объединить все шаблоны в один, используя оператор or, как предлагают некоторые люди, но не просто соедините их вместе с |. Это будет плохо работать, если любой из ваших шаблонов содержит оператор or.

Я бы рекомендовал, по крайней мере, группировать ваши шаблоны, используя круглые скобки, например:

foreach ($patterns as $pattern)
{
  $grouped_patterns[] = "(" . $pattern . ")";
}
$master_pattern = implode($grouped_patterns, "|");

Но ... Я не совсем уверен, что это закончится быстрее. Что-то должно пройти через них, будь то preg_match или PHP. Если бы мне пришлось угадывать, я бы предположил, что отдельные совпадения были бы такими же быстрыми, их было бы легче читать и поддерживать.

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

Делая так:

foreach ($strings_to_match as $string_to_match)
{
  if (strpos($page, $string_to_match) !== false))
  {
    // etc.
    break;
  }
}
foreach ($pattern_array as $pattern)
{
  if (preg_match($pattern, $page))
  {
    // etc.
    break;
  } 
}

и избегание как можно большего числа preg_match(), вероятно, будет вашим лучшим приобретением. strpos() это лот быстрее, чем preg_match().

11 голосов
/ 26 марта 2009
// assuming you have something like this
$patterns = array('a','b','\w');

// converts the array into a regex friendly or list
$patterns_flattened = implode('|', $patterns);

if ( preg_match('/'. $patterns_flattened .'/', $string, $matches) )
{
}

// PS: that's off the top of my head, I didn't check it in a code editor
2 голосов
/ 10 сентября 2012

Если ваши шаблоны не содержат много пробелов, другой вариант - отказаться от массивов и использовать модификатор /x. Теперь ваш список регулярных выражений будет выглядеть так:

$regex = "/
pattern1|   # search for occurences of 'pattern1'
pa..ern2|   # wildcard search for occurences of 'pa..ern2'
pat[ ]tern| # search for 'pat tern', whitespace is escaped
mypat       # Note that the last pattern does NOT have a pipe char
/x";

С модификатором /x пробел полностью игнорируется, за исключением случаев, когда он находится в классе символов или ему предшествует обратная косая черта. Комментарии как выше также разрешены.

Это позволит избежать зацикливания массива.

1 голос
/ 26 марта 2009

Если вы просто ищете наличие строки в другой строке, используйте strpos, поскольку это быстрее.

В противном случае вы можете просто перебирать массив шаблонов, каждый раз вызывая preg_match.

0 голосов
/ 09 августа 2018

Вы можете объединить все шаблоны из списка в одно регулярное выражение, используя функцию implode () php. Затем проверьте вашу строку сразу, используя preg_match () php function.

$patterns = array(
  'abc',
  '\d+h',
  '[abc]{6,8}\-\s*[xyz]{6,8}',
);

$master_pattern = '/(' . implode($patterns, ')|(') . ')/'

if(preg_match($master_pattern, $string_to_check))
{
  //do something
}

Конечно, может быть даже меньше кода, использующего встроенную функцию implode () в условии if () вместо переменной $master_pattern.

0 голосов
/ 26 марта 2009

Как насчет выполнения str_replace() для HTML, который вы получаете, используя свой массив, и затем проверки, равен ли исходный HTML оригиналу? Это было бы очень быстро:

 $sites = array(
      'you_tube' => array('dead', 'moved'),
      ...
 );
 foreach ($sites as $site => $deadArray) {
     // get $html
     if ($html == str_replace($deadArray, '', $html)) { 
         // video is live
     }
 }
0 голосов
/ 26 марта 2009

Если у вас есть набор шаблонов, вы можете объединить их в одно регулярное выражение и сопоставить их. Нет необходимости в петле.

...