1

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

但我觉得数组映射类型函数或更好的 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

4 回答 4

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

所以在一天结束时,我们不得不编写一些代码,但不仅原始问题的解决方案很巧妙,而且我们还获得了一段通用的、可重用的代码来帮助我们。

于 2012-06-26T05:41:01.923 回答
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);
}
于 2012-06-26T06:07:40.827 回答
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

于 2012-06-26T05:57:13.050 回答
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

也许有一些理由保留数组键 => 值来完成替换?

于 2012-06-26T18:08:49.713 回答