PHP更换/匹配$ 1的更好方法

时间:2012-06-26 04:23:07

标签: php

我正在尝试用其他网址替换网址中的$1, $2, $3个变量。 您可以复制粘贴下面的示例并查看我的解决方案。

但我觉得有一种更优雅的方式,使用数组映射类型函数或更好的preg_replace类型的东西。我只需要向正确的方向踢,你能帮忙吗?

    <?php
    /**
    *  Key = The DESIRED string
    *  Value = The ORIGINAL value
    *
    * Desired Result: project/EXAMPLE/something/OTHER
    */
    $data = array(
        'project/$1/details/$2' => 'newby/EXAMPLE/something/OTHER'
    );

    foreach($data as $desiredString => $findMe)
    {
        /**
        * Turn these URI's into arrays
        */
        $desiredString = explode('/', $desiredString);
        $findMe = explode('/', $findMe);

        /**
        * Store the array position of the match
        */
        $positions = array();
        foreach($desiredString as $key => $value) {
            /**
            * Look for $1, $2, $3, etc..
            */
            if (preg_match('#(\$\d)#', $value)) {
                $positions[$key] = $value;
            }
        }

        /**
        * Loop through the positions
        */
        foreach($positions as $key => $value){
            $desiredString[$key] = $findMe[$key];
        }

        /**
        * The final result
        */
        echo implode('/', $desiredString);
    }

4 个答案:

答案 0 :(得分:2)

有时你运气不好,直接解决问题所需的功能就不存在了。每种语言都会发生这种情况,无论它有多少库和内置函数。

我们将不得不写一些代码。我们还需要解决一个特定的问题。最终,我们希望我们对问题的解决方案同样干净,就像我们首先拥有理想的功能一样。因此,无论我们编写什么代码,我们都希望大部分代码都不受影响,这可能意味着我们希望将大部分代码放在单独的函数或类中。但我们不只是想抛弃任意代码,因为我们所有的函数和类都应该是可重用的。

我的方法是从解决方案中提取有用的通用模式,将其作为函数编写,然后使用该函数重写原始解决方案(这将简化它)。为了找到这种一般模式,我将问题变得更大,因此可能适用于更多情况。

我最终创建了函数array array_multi_walk(callback $callback [, array $array1 [, array $array2 ... ]])。此函数同时遍历每个数组,并使用$callback选择要保留的元素。

这就是使用此功能的解决方案。

$chooser = function($a, $b) {
  return strlen($a) >= 2 && $a[0] == '$' && ctype_digit($a[1])
    ? $b : $a;
};

$data = array(
  'project/$1/details/$2' => 'newby/EXAMPLE/something/OTHER'
);

$explodeSlashes = function($a) { return explode('/', $a); };
$find = array_map($explodeSlashes, array_keys($data));
$replace = array_map($explodeSlashes, array_values($data));

$solution = array_multi_walk(
    function($f, $r) use ($chooser) {
        return array_multi_walk($chooser, $f, $r);
    },
    $find, $replace);

并且,根据需要,array_multi_walk可用于其他问题。例如,这会将所有元素相加。

$sum = function() {
  return array_sum(func_get_args());
};

var_dump(array_multi_walk($sum, array(1,2,3), array(1,2,3), array(10)));
// prints the array (12, 4, 6)

您可能希望对array_multi_walk进行一些调整。例如,如果回调通过数组而不是单独的参数获取元素可能会更好。当任何数组用完元素时,可能应该有选项标志停止,而不是填充空值。

以下是我提出的array_multi_walk的实现。

function array_multi_walk($callback)
{
  $arrays = array_slice(func_get_args(), 1);
  $numArrays = count($arrays);
  if (count($arrays) == 0) return array();
  $result = array();
  for ($i = 0; ; ++$i) {
    $elementsAti = array();
    $allNull = true;
    for ($j = 0; $j < $numArrays; ++$j) {
      $element = array_key_exists($i, $arrays[$j]) ? $arrays[$j][$i] : null;
      $elementsAti[] = $element;
      $allNull = $allNull && $element === null;
    }
    if ($allNull) break;

    $result[] = call_user_func_array($callback, $elementsAti);
  }
  return $result;
}

所以在一天结束时,我们不得不编写一些代码,但不仅是原始问题的解决方案,我们还获得了一个通用的,可重复使用的代码片段,以便以后帮助我们。

答案 1 :(得分:2)

为什么不应该有$ 2,$ 4但$ 1,$ 2?如果你可以改变你的阵列那么它可以用3或4行代码解决。

$data = array(
    'project/$2/details/$4' => 'newby/EXAMPLE/something/OTHER'
);

foreach($data as $desiredString => $findMe)
{
    $regexp = "#(".implode(')/(',explode('/',$findMe)).")#i";
    echo preg_replace($regexp,$desiredString,$findMe);
}

答案 2 :(得分:1)

我通过删除评论来缩短您的代码,以提高可读性。我正在使用array_map,映射函数决定返回什么值:

<?php

function replaceDollarSigns($desired, $replace)
{
    return preg_match('#(\$\d)#', $desired) ? $replace : $desired;
}

$data = array(
    'project/$1/details/$2' => 'newby/EXAMPLE/something/OTHER',
);

foreach($data as $desiredString => $findMe)
{
    $desiredString = explode('/', $desiredString);
    $findMe = explode('/', $findMe);
    var_dump(implode('/', array_map('replaceDollarSigns', $desiredString, $findMe)));
}
?>

工作示例:http://ideone.com/qVLmn

您也可以使用create_function

省略该功能
<?php

$data = array(
    'project/$1/details/$2' => 'newby/EXAMPLE/something/OTHER',
);

foreach($data as $desiredString => $findMe)
{
    $desiredString = explode('/', $desiredString);
    $findMe = explode('/', $findMe);
    $result = array_map(
        create_function(
            '$desired, $replace',
            'return preg_match(\'#(\$\d)#\', $desired) ? $replace : $desired;'
        ),
        $desiredString,
        $findMe);
    var_dump(implode('/', $result));
}
?>

工作示例:http://ideone.com/OC0Ak

答案 3 :(得分:0)

只是说,为什么不在preg_replace中使用数组模式/替换?像这样:

<?php
/**
*  Key = The DESIRED string
*  Value = The ORIGINAL value
*
* Desired Result: project/EXAMPLE/something/OTHER
*/
$data = array(
    'project/$1/details/$2' => 'newby/EXAMPLE/details/OTHER'
);
$string = 'project/$1/details/$2';

$pattern[0] = '/\$1/';
$pattern[1] = '/\$2/';
$replacement[0] = 'EXAMPLE';
$replacement[1] = 'OTHER';
$result = preg_replace($pattern, $replacement, $string);

echo $result;

我认为这比你正在寻找的要容易得多。你可以看到它在这里工作:http://codepad.org/rCslRmgs

也许有理由保持数组键=&gt;完成替换的价值?