Как вы выполняете preg_match, где шаблоном является массив, в php?

StackOverflow https://stackoverflow.com/questions/683702

  •  22-08-2019
  •  | 
  •  

Вопрос

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

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

Это было полезно?

Решение

Прежде всего, если вы буквально только делаете десятки каждый минута, тогда я бы не стал сильно беспокоиться о производительности в этом случае.Эти соответствия выполняются довольно быстро, и я не думаю, что у вас возникнут проблемы с производительностью, если вы выполните итерацию по вашему массиву patterns и вызовете 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().

Другие советы

// 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

Если ваши шаблоны не содержат много пробелов, другим вариантом было бы отказаться от массивов и использовать /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 модификатор, пробел полностью игнорируется, за исключением случаев, когда он находится в классе символов или перед ним стоит обратная косая черта.Комментарии, подобные приведенным выше, также разрешены.

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

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

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

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

Как насчет того, чтобы сделать 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
     }
 }

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

$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 переменная.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top