替换字符串中的占位符以使用替换字符串的所有组合创建字符串数组

发布于 2024-10-02 10:07:00 字数 635 浏览 8 评论 0原文

对于我正在从事的项目,我有一个带有占位符的基本 URI,并且我想使用 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 函数......

For a project I'm working on, I have a base URI with placeholders and I want to generate all the possible combinations from an array of possible values for each placeholder using PHP.

More concretely:

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

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

I'd like ending up having the following array:

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"
}

Not to mention I should be able to add more placeholders to generate more computed URIs, of course, so the solution should work recursively.

I might be overtired these days, but I'm getting stuck at achieving this simply, and I'm sure there's a simple way, perhaps even with built-in PHP functions…

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

无声静候 2024-10-09 10:07:01

这是可行的,但它不是那么优雅,因为需要摆脱占位符数组键:

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

?>

This work, but it's not so elegant because of the need to get rid of the placeholder array keys :

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

?>
青衫负雪 2024-10-09 10:07:00
$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 多么喜欢递归)。这应该允许替换相当数量的模式,而不会以疯狂的深度递归。

$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";
}

The idea here is to list in an array all the possible combinations for the replacements. The function expandCombinations just adds one level of depth in the combinations for each new pattern to replace with no recursion (we know how PHP loves recursion). This should allow for a decent number of patterns to replace without recursing at an insane depth.

梓梦 2024-10-09 10:07:00
    <?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& 
    ) 
    ?>

它可以处理无限数量的占位符和占位符。值的数量不受限制

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

It handles unlimited count of placeholders & unlimited count of values

流年已逝 2024-10-09 10:07:00

一种递归解决方案:

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

A recursive solution:

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;
    }
}

Each call to the function pops one placeholder off the array and loops through its potential values enumerating through all the remaining placeholder values for each one. The complexity is O(k^n) where k is the average number of replacements for each placeholder and n is the number of placeholders.

My PHP is a little rusty; let me know if I got any of the syntax wrong.

×纯※雪 2024-10-09 10:07:00
foreach($placeholders['%foo%'] as $foo){
    foreach($placeholders['%bar%'] as $bar){
      $container[] = str_replace(array('%foo%','%bar%'),array($foo,$bar),$uri);
    }
}
foreach($placeholders['%foo%'] as $foo){
    foreach($placeholders['%bar%'] as $bar){
      $container[] = str_replace(array('%foo%','%bar%'),array($foo,$bar),$uri);
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文