如何在php中执行模式为数组的preg_match?

时间:2009-03-25 22:09:32

标签: php arrays preg-match

我有一个充满模式的数组,我需要匹配。除了for()循环之外,还有什么办法吗?我试图以最少CPU密集的方式做到这一点,因为我将每分钟做几十个。

真实世界的例子是,我正在建立一个链接状态检查器,它将检查各个在线视频网站的链接,以确保视频仍然有效。每个域都有几个“死关键字”,如果在页面的html中找到它们,则表示该文件已被删除。它们存储在数组中。我需要匹配数组的内容,与页面的html输出相匹配。

7 个答案:

答案 0 :(得分:20)

首先,如果您确实只是几十分钟,那么我不会非常担心这种情况下的表现。这些匹配非常快,我不认为你会通过迭代模式数组并单独调用preg_match来解决性能问题:

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

您确实可以使用or运算符将所有模式合并为一个,就像一些人建议的那样,但不要只是将它们与|一起拍打。如果您的任何模式包含或运算符,这将会严重破坏。

我建议至少使用括号分组您的模式,如:

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

但是......我不确定这最终是否会更快。 Something 必须遍历它们,无论是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()比<{1}}快很多

答案 1 :(得分:11)

// 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 :(得分:2)

如果您的模式不包含许多空格,则另一个选项是避开数组并使用/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修饰符时,完全忽略空格,除非在字符类中或以反斜杠开头。也允许上述评论。

这样可以避免循环遍历数组。

答案 3 :(得分:1)

如果您只是在另一个字符串中搜索字符串,请使用strpos,因为它更快。

否则,您可以遍历模式数组,每次都调用preg_match。

答案 4 :(得分:0)

如果你有一堆模式,你可以做的是将它们连接在一个正则表达式中并匹配它。不需要循环。

答案 5 :(得分:0)

如果对使用数组获得的HTML进行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
     }
 }

答案 6 :(得分:0)

您可以使用implode() 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
}

当然,在“ if()”条件下使用implode()内联而不是$master_pattern变量,甚至可以有更少的代码。