通配符阵列比较 - 提高效率

时间:2012-07-22 20:47:28

标签: php loops foreach while-loop preg-match

我有两个我正在比较的数组,我想知道是否有更有效的方法来实现它。

第一个数组是用户提交的值,第二个数组是允许的值,其中一些可能包含数字符号的通配符,例如。

// user submitted values
$values = array('fruit' => array(
        'apple8756apple333',
        'banana234banana',
        'apple4apple333',
        'kiwi435kiwi'
        ));

//allowed values
$match = array('allowed' => array(
        'apple*apple333',
        'banana234banana',
        'kiwi*kiwi'
        ));

我需要知道第一个数组中的所有值是否与第二个数组中的值匹配。

这就是我正在使用的:

// the number of values to validate
$valueCount = count($values['fruit']);

// the number of allowed to compare against
$matchCount = count($match['allowed']);

// the number of values passed validation
$passed = 0;

// update allowed wildcards to regular expression for preg_match
foreach($match['allowed'] as &$allowed)
{
    $allowed = str_replace(array('*'), array('([0-9]+)'), $allowed);
}

// for each value match against allowed values
foreach($values['fruit'] as $fruit)
{
    $i = 0;
    $status = false;
    while($i < $matchCount && $status == false)
    {
        $result = preg_match('/' . $match['allowed'][$i] . '/', $fruit);
        if ($result)
        {
            $status = true;
            $passed++;
        }
        $i++;
    }
}

// check all passed validation
if($passed === $valueCount)
{
    echo 'hurray!';
}
else
{
    echo 'fail';
}

我觉得我可能错过了一个PHP函数,它比foreach循环中的while循环做得更好。或者我错了吗?

更新:抱歉,我忘了提及,数值可能会在值内超过1个位置,但只会有1个通配符。我已经更新了数组来代表这个。

2 个答案:

答案 0 :(得分:2)

如果你不希望在另一个中有一个循环,那么如果你对$match正则表达式进行分组会更好。

您可以使用更少的代码获得整个功能,这可能比您当前的解决方案更有效:

// user submitted values
$values = array(
          'fruit' => array(
              'apple8756apple',
              'banana234banana',
              'apple4apple',
              'kiwi51kiwi'
            )
          );


$match = array(
           'allowed' => array(
              'apple*apple',
              'banana234banana',
              'kiwi*kiwi'
            )
          );

$allowed = '('.implode(')|(',$match['allowed']).')';
$allowed = str_replace(array('*'), array('[0-9]+'), $allowed);


foreach($values['fruit'] as $fruit){
  if(preg_match('#'.$allowed.'#',$fruit))
    $matched[] = $fruit;
}

print_r($matched);

见这里:http://codepad.viper-7.com/8fpThQ

答案 1 :(得分:1)

尝试用'*'替换第一个数组中的/ \ d + /,然后在2个数组之间执行array_diff()

编辑:澄清之后,这是一个更精确的方法:

<?php
    $allowed = str_replace("*", "\d+", $match['allowed']);
    $passed = 0;
    foreach ($values['fruit'] as $fruit) {
        $count = 0;
        preg_replace($allowed, "", $fruit, -1, $count);    //preg_replace accepts an array as 1st argument and stores the replaces done on $count;
        if ($count) $passed++;
    }
    if ($passed == sizeof($values['fruit']) {
        echo 'hurray!';
    } else {
        echo 'fail';
    }
?>

上面的解决方案并没有消除对嵌套循环的需求,但它只是让PHP执行内部循环,可能更快(你应该实际对它进行基准测试)