2 Stimmen

Rekursive Ersetzung von Zeichenketten mit PHP

Für ein Projekt, an dem ich arbeite, habe ich eine Basis-URI mit Platzhaltern, und ich möchte alle möglichen Kombinationen aus einem Array von möglichen Werten für jeden Platzhalter mit PHP generieren.

Konkreter:

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

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

Ich möchte, dass ich am Ende die folgende Anordnung habe:

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

Ganz zu schweigen davon, dass ich in der Lage sein sollte, weitere Platzhalter hinzuzufügen, um weitere berechnete URLs zu generieren, so dass die Lösung rekursiv funktionieren sollte.

Vielleicht bin ich in diesen Tagen übermüdet, aber ich komme einfach nicht weiter, und ich bin sicher, dass es einen einfachen Weg gibt, vielleicht sogar mit eingebauten PHP-Funktionen

Anhaltspunkte? Jede Hilfe wird sehr geschätzt.

3voto

Mohammad Mazaz Punkte 326
    <?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& 
    ) 
    ?>

Es verarbeitet eine unbegrenzte Anzahl von Platzhaltern und eine unbegrenzte Anzahl von Werten

3voto

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

Hier geht es darum, in einem Array alle möglichen Kombinationen für die Ersetzungen aufzulisten. Die Funktion expandCombinations fügt den Kombinationen für jedes neue zu ersetzende Muster ohne Rekursion (wir wissen, wie sehr PHP Rekursionen liebt) einfach eine Ebene tiefer hinzu. Dies sollte eine anständige Anzahl von zu ersetzenden Mustern ermöglichen, ohne in einer irrsinnigen Tiefe zu rekursieren.

2voto

Zack Bloom Punkte 8219

Eine rekursive Lösung:

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

Bei jedem Aufruf der Funktion wird ein Platzhalter aus dem Array entfernt und in einer Schleife durch die möglichen Werte geführt, wobei alle verbleibenden Platzhalterwerte für jeden einzelnen aufgezählt werden. Die Komplexität ist O(k^n), wobei k die durchschnittliche Anzahl der Ersetzungen für jeden Platzhalter und n die Anzahl der Platzhalter ist.

Mein PHP ist ein wenig eingerostet; lassen Sie es mich wissen, wenn ich etwas an der Syntax falsch verstanden habe.

1voto

Juan Cortés Punkte 19638
foreach($placeholders['%foo%'] as $foo){
    foreach($placeholders['%bar%'] as $bar){
      $container[] = str_replace(array('%foo%','%bar%'),array($foo,$bar),$uri);
    }
}

0voto

Das funktioniert, ist aber nicht so elegant, weil die Platzhalter-Array-Schlüssel entfernt werden müssen:

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

?>

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X