【问题标题】:Recursive strings replacement with PHP用 PHP 替换递归字符串
【发布时间】:2011-05-09 11:48:30
【问题描述】:

对于我正在处理的项目,我有一个带有占位符的基本 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"
}

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

这些天我可能太累了,但我一直坚持简单地实现这一点,而且我确信有一种简单的方法,甚至可能使用内置 PHP 函数......

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

【问题讨论】:

    标签: php arrays recursion replace


    【解决方案1】:
        <?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& 
        ) 
        ?>
    

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

    【讨论】:

    • 非常好!它只是缺少原始 URI 中的字符串替换,但它绝对是一个有趣的解决方案。
    【解决方案2】:
    $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 是如何喜欢递归的)。这应该允许替换相当数量的模式,而不会以疯狂的深度递归。

    【讨论】:

      【解决方案3】:

      递归解决方案:

      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 有点生锈了;如果我有任何语法错误,请告诉我。

      【讨论】:

      • Pythonista 被发现了,对吧? ;) 不幸的是,我花了一些时间来调整代码,但即使我认为我明白了,我也没有设法让它工作......
      【解决方案4】:
      foreach($placeholders['%foo%'] as $foo){
          foreach($placeholders['%bar%'] as $bar){
            $container[] = str_replace(array('%foo%','%bar%'),array($foo,$bar),$uri);
          }
      }
      

      【讨论】:

      • 是的,当然这适用于两个级别,但这并不是真正的递归(我应该能够添加尽可能多的占位符,而无需手动嵌入 foreach 循环)。我编辑了问题以更清楚地反映这种需求。
      • 这不是一个好方法,假设您有 10 个 plceholder 和每个 3 个值,这意味着 10 个嵌入式循环。它将呈指数增长,这意味着 3 的 10 次方,即 50K+ 循环
      • infinity> 是的,我知道,但是我可以有一个配置设置,允许最大递归级别和/或占位符数量,以避免最终产生黑洞。
      • 我的函数允许任意数量的值。
      • Aurel300> 酷!它在哪里? :)
      【解决方案5】:

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

      <?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);
      
      ?>
      

      【讨论】:

        猜你喜欢
        • 2011-09-27
        • 1970-01-01
        • 2017-04-24
        • 2011-09-03
        • 2013-08-21
        • 2019-01-03
        • 1970-01-01
        • 2023-03-04
        • 1970-01-01
        相关资源
        最近更新 更多