用PHP替换递归字符串

时间:2010-11-13 10:22:04

标签: php arrays recursion replace

对于我正在处理的项目,我有一个带占位符的基URI,并且我希望使用PHP从每个占位符的可能值数组中生成所有可能的组合。

更具体地说:

<?php
$uri = "foo/bar?foo=%foo%&bar=%bar%";

$placeholders = array(
  '%foo%' => array('a', 'b'),
  '%bar%' => array('c', 'd'),
  // ...
);

我想最终得到以下数组:

array(4) {
  [0]=>
  string(23) "foo/bar?foo=a&bar=c"
  [1]=>
  string(23) "foo/bar?foo=a&bar=d"
  [2]=>
  string(19) "foo/bar?foo=b&bar=c"
  [3]=>
  string(19) "foo/bar?foo=b&bar=d"
}

更不用说我应该能够添加更多的占位符来生成更多的计算uris,当然,所以解决方案应该递归地工作。

这些天我可能会过度疲惫,但我很难实现这一点,而且我确信有一种简单的方法,甚至可能还有内置的PHP函数......

提示?任何帮助非常感谢。

5 个答案:

答案 0 :(得分:4)

    <?php
    function rec($values,$keys,$index,$str,&$result)
    {
    if($index<count($values))
    foreach($values[$index] as $val)
    rec($values,$keys,$index+1,$str.substr($keys[$index],1,strlen($keys[$index])-2)."=".$val."&",$result);
    else
    $result[count($result)] = $str;
    }



// Now for test


    $placeholders = array(
      '%foo%' => array('a', 'b'),
      '%bar%' => array('c', 'd' , 'h'),
    );
    $xvalues = array_values($placeholders) ;
    $xkeys = array_keys($placeholders) ;
    $result = array();  
    rec($xvalues,$xkeys,0,"",$result);  // calling the recursive function
    print_r($result);
    // the result will be:
    Array ( 
    [0] => foo=a&bar=c& 
    [1] => foo=a&bar=d& 
    [2] => foo=a&bar=h& 
    [3] => foo=b&bar=c& 
    [4] => foo=b&bar=d& 
    [5] => foo=b&bar=h& 
    ) 
    ?>

它处理无限数量的占位符和&amp;无限数量的值

答案 1 :(得分:3)

$uri= "foo/bar?foo=%foo%&bar=%bar%&baz=%baz%";
$placeholders = array(
    '%foo%' => array('a', 'b'),
    '%bar%' => array('c', 'd', 'e'),
    '%baz%' => array('f', 'g')
    );

//adds a level of depth in the combinations for each new array of values
function expandCombinations($combinations, $values)
{
    $results = array();
    $i=0;
    //combine each existing combination with all the new values
    foreach($combinations as $combination) {
        foreach($values as $value) {
            $results[$i] = is_array($combination) ? $combination : array($combination);
            $results[$i][] = $value;
            $i++;
        }
    }
    return $results;
}   

//generate the combinations
$patterns = array();
foreach($placeholders as $pattern => $values)
{
    $patterns[] = $pattern;
    $combinations = isset($combinations) ? expandCombinations($combinations, $values) : $values;
}

//generate the uris for each combination
foreach($combinations as $combination)
{
    echo str_replace($patterns, $combination, $uri),"\n";
}

这里的想法是在数组中列出替换的所有可能组合。函数expandCombinations只是在每个新模式的组合中添加一个深度级别来替换没有递归(我们知道PHP如何喜欢递归)。这应该允许替换相当数量的模式而不会在疯狂的深度进行递归。

答案 2 :(得分:2)

递归解决方案:

function enumerate($uri, $placeholders){
    $insts = array();
    if (!empty($placeholders)){
        $key = array_keys($placeholders)[0];
        $values = array_pop($placeholders);

        foreach($values => $value){
            $inst = str_replace($uri, $key, $value);
            $insts = array_merge($insts, (array)enumerate($inst, $placeholders));
        }
        return $insts;
    } else {
        return $uri;
    }
}

对函数的每次调用都会弹出数组中的一个占位符,并循环遍历其潜在值,枚举每个占位符的所有剩余占位符值。复杂度为O(k ^ n),其中k是每个占位符的平均替换次数,n是占位符的数量。

我的PHP有点生疏;如果我的语法错误,请告诉我。

答案 3 :(得分:1)

foreach($placeholders['%foo%'] as $foo){
    foreach($placeholders['%bar%'] as $bar){
      $container[] = str_replace(array('%foo%','%bar%'),array($foo,$bar),$uri);
    }
}

答案 4 :(得分:0)

这项工作,但它不是那么优雅,因为需要摆脱占位符数组键:

<?php

    /*
     * borrowed from http://www.theserverpages.com/php/manual/en/ref.array.php
     * author: skopek at mediatac dot com 
     */
    function array_cartesian_product($arrays) {
        //returned array...
        $cartesic = array();

        //calculate expected size of cartesian array...
        $size = sizeof($arrays) > 0 ? 1 : 0;

        foreach ($arrays as $array) {
            $size *= sizeof($array);
        }

        for ($i = 0; $i < $size; $i++) {
            $cartesic[$i] = array();

            for ($j = 0; $j < sizeof($arrays); $j++) {
                $current = current($arrays[$j]); 
                array_push($cartesic[$i], $current);    
            }

            //set cursor on next element in the arrays, beginning with the last array
            for ($j = sizeof($arrays) - 1; $j >= 0; $j--) {
                //if next returns true, then break
                if (next($arrays[$j])) {
                    break;
                } else { //if next returns false, then reset and go on with previuos array...
                    reset($arrays[$j]);
                }
            }
        }

        return $cartesic;
    }

    $uri = "foo/bar?foo=%foo%&bar=%bar%";
    $placeholders = array(
        0 => array('a', 'b'), // '%foo%'
        1 => array('c', 'd'), // '%bar%'
    );

    //example
    header("Content-type: text/plain");
    $prod = array_cartesian_product($placeholders);
    $result = array();

    foreach ($prod as $vals) {
        $temp = str_replace('%foo%', $vals[0], $uri);
        $temp = str_replace('%bar%', $vals[1], $temp);
        array_push($result, $temp);
    }

    print_r($result);

?>