2010-11-13 6 views
2

Pour un projet sur lequel je travaille, j'ai un URI de base avec des espaces réservés et je veux générer toutes les combinaisons possibles à partir d'un tableau de valeurs possibles pour chaque espace réservé utilisant PHP.Remplacement de chaînes récursives avec PHP

Plus concrètement:

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

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

Je voudrais finir avec le tableau suivant:

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

Sans parler, je devrais pouvoir ajouter plus de générer des espaces réservés à uri plus calculés, de Bien sûr, la solution devrait fonctionner de manière récursive.

je pourrais être surmené ces jours-ci, mais je suis rester coincé à la réalisation de cet simplement, et je suis sûr qu'il ya un moyen simple, peut-être même avec des fonctions PHP BUILTIN ...

Conseils? Toute aide très appréciée.

Répondre

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

L'idée ici est de la liste dans un tableau toutes les combinaisons possibles pour les remplacements. La fonction expandCombinations ajoute juste un niveau de profondeur dans les combinaisons pour chaque nouveau motif à remplacer sans récursion (nous savons comment PHP aime la récursivité). Cela devrait permettre à un nombre décent de modèles à remplacer sans récurer à une profondeur folle.

+0

Solution douce, fonctionne parfaitement: vous avez gagné mon vote! – NiKo

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

Oui, cela fonctionne pour deux niveaux mais ce n'est pas vraiment récursif (je devrais être capable d'ajouter autant d'espaces réservés que je veux sans embarquer foreach manuellement). J'ai édité la question pour refléter ce besoin plus clairement. – NiKo

+0

Ce n'est pas une bonne approche, imaginez que vous avez 10 plceholders et 3 valeurs pour chacune, ce qui signifie 10 boucles intégrées. Il va augmenter exponentiellement ce que signifie 3 à la puissance de 10 qui sont 50K + boucles – infinity

+0

C'est bon pour deux niveaux, je vous ai mal lu, désolé. –

0

Ce travail, mais ce n'est pas si élégant en raison de la nécessité de se débarrasser des clés du tableau d'espace réservé:

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

?> 
2

Une solution récursive:

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

Chaque appel à la La fonction renvoie un espace réservé du tableau et boucle sur ses valeurs potentielles en énumérant toutes les valeurs d'espace réservé restantes pour chacune d'entre elles. La complexité est O (k^n) où k est le nombre moyen de remplacements pour chaque espace réservé et n est le nombre d'espaces réservés.

Mon PHP est un peu rouillé; faites-moi savoir si j'ai une mauvaise syntaxe.

+0

Pythonista repéré, non? ;) malheureusement, j'ai passé quelques fois à tordre le code mais je n'ai pas réussi à le faire fonctionner même si je pense avoir l'idée ... – NiKo

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

Il gère le nombre illimité d'espaces réservés & nombre illimité de valeurs

+0

Très sympa! il ne manquait que les remplacements de cordes de l'URI d'origine, mais c'est une solution définitivement intéressante. – NiKo