在PHP数组中搜索和替换值

47

我正在寻找一些标准PHP函数来替换数组中的某些值,但出乎意料地没有找到任何相关函数,所以我不得不自己编写:

function array_replace_value(&$ar, $value, $replacement)
{
    if (($key = array_search($ar, $value)) !== FALSE) {
        $ar[$key] = $replacement;
    }
}

但我仍然想知道 - 对于这样一个简单的事情,肯定已经有一些可以解决它的函数!或者可能有比我发明的这个方法更简单的解决方案?

请注意,此函数只会替换一个出现。我正在寻找类似替换单个出现的现有解决方案,以及替换所有出现的解决方案。


请注意,数组是按值传递的。您需要从函数中返回新数组(以匹配array_*函数的行为)或通过引用传递$ararray_replace_value函数。 - outis
谢谢@outis,与此同时我在调试过程中自己意识到了这一点 :) - Tomas
function array_replace_value(array $subject, $search, $replace) { if (($key = array_search($subject, $search)) !== false) { $subject[$key] = $replace; } return $subject; }并不是一个更短的函数或者其他什么,但是这个更新后的函数将与其他PHP数组_ *函数匹配,并且参数命名也更像str_replace。但是你的函数对我来说非常方便,我认为没有更短的方法了。 - Gummibeer
@Gummibeer也许你应该给出一个答案,评论中的代码看起来不太好看 :-) - Tomas
@TMS 我知道,但这并不是真正的答案,因为它几乎与问题中的代码相同。但如果你愿意的话,我可以做。 ;) - Gummibeer
显示剩余7条评论
12个回答

40

不要使用一个只能替换数组中某个值的函数,而是使用更加通用的array_map函数:

array_map(function ($v) use ($value, $replacement) {
    return $v == $value ? $replacement : $v;
}, $arr);

使用值=>替换数组来替换多个值的多个出现:

array_map(function ($v) use ($replacement) {
    return isset($replacement[$v]) ? $replacement[$v] : $v;
}, $arr);
要替换一个值的单个出现,您可以像使用 array_search 一样操作。因为实现代码非常简短,所以PHP开发人员没有太多理由创建一个标准函数来执行此任务。并不是说如果您经常需要这样做,就没有必要创建这样的函数。

谢谢outis提供的好答案,我不知道这个语法,但是使用map和自定义代码可以解决问题 - 可能效率不高?我更喜欢像Raghav那样的“硬编码”解决方案。 - Tomas
@Tomas:你所指的语法是指匿名函数和闭包吗?除了添加"use"说明符外,这更多是语义而不是语法。至于效率,如果有影响,那么它是可以忽略不计的(除非您在每个请求中对数千个数组执行替换)。影响性能的一个因素是,每次调用array_*函数都会创建一个额外的数组作为其结果:在这里是一个,在Raghav的代码中则是三个。像往常一样,分析是确定性能的最佳方法。 - outis
1
请注意,Raghav的代码中没有任何硬编码,因为它们都是参数化的(数组、要替换的值和替换值)。硬编码很少会带来明显的性能优势,因为变量查找的成本很小。 - outis
感谢outis提供的回答...但是最终我很幸运地使用了Raghav的解决方案,因为我们托管提供商的服务器仍在运行PHP 5.2,所以我不得不从我的代码中删除所有匿名函数...(我在PHP 5.3上开发,所以有点“背叛”...) - Tomas
@Tomas:我感同身受。闭包的支持让 PHP 变得更加可接受。 - outis

32
虽然没有一个函数可以等效于示例代码,但是您可以使用array_keys(带有可选的搜索值参数)、array_fillarray_replace来实现同样的功能:

Tomas编辑:代码并没有起作用,已经更正:

$ar = array_replace($ar,
    array_fill_keys(
        array_keys($ar, $value),
        $replacement
    )
);

array_replace() 不是假设你已经知道键吗?原帖的作者正在寻找按值搜索和替换。 - Michael Berkowski
array_replace 按键替换,而非按值替换。 - outis
@RaghavBhushan:如果你有这个键,你就不需要使用array_replace - outis
@RaghavBhushan:(关于您的原始写作)<br/>不是语义化的。此外,在SO上您不需要它。 - outis
@RaghavBhushan:Tomas的函数已经使用了array_search来查找要替换的单个项目,而这个答案的第一部分已经涵盖了array_replace - outis

15

如果性能是一个问题,可能需要考虑不在array_map()中创建多个函数。请注意,isset()非常快,该解决方案根本不调用任何其他函数。

$replacements = array(
    'search1' => 'replace1',
    'search2' => 'replace2',
    'search3' => 'replace3'
);
foreach ($a as $key => $value) {
    if (isset($replacements[$value])) {
        $a[$key] = $replacements[$value];
    }
}

7

尝试使用这个函数。

public function recursive_array_replace ($find, $replace, $array) {
    if (!is_array($array)) {
        return str_replace($find, $replace, $array);
    }

    $newArray = [];
    foreach ($array as $key => $value) {
        $newArray[$key] = recursive_array_replace($find, $replace, $value);
    }
    return $newArray;
}

干杯!


这段未经解释的递归代码进行部分匹配/替换,不一定是整个值的替换。 - mickmackusa

6

$ar[array_search('green', $ar)] = 'value';


5
你能为你的代码添加一些解释吗?如果 array_search 返回 false 会怎么样? - Nico Haase
我不建议研究人员使用这个不稳定且未经解释的代码片段。 - mickmackusa

4

根据你想要查找和替换的是值、键还是两者,你可以像下面这样做:

$array = json_decode( str_replace( $replace, $with, json_encode( $array ) ), true );

我不是说这是最高效或最优雅的,但它简单明了。


这将进行部分匹配/替换,而不一定是整个值的替换。 - mickmackusa

4

array_walk()和回调函数有什么关系?

$array = ['*pasta', 'cola', 'pizza'];
$search = '*';
$replace = '\*';
array_walk($array,
    function (&$v) use ($search, $replace){
        $v = str_replace($search, $replace, $v);    
    }                                                                     
);  
print_r($array);

这将进行部分匹配/替换,而不一定是整个值的替换。 - mickmackusa

1

基于 Deept Raghav 的回答,我创建了以下解决方案,它可以进行正则表达式搜索。

$arr = [
    'Array Element 1',
    'Array Element 2',
    'Replace Me',
    'Array Element 4',
];

$arr = array_replace(
    $arr,
    array_fill_keys(
        array_keys(
            preg_grep('/^Replace/', $arr)
        ),
        'Array Element 3'
    )
);

echo '<pre>', var_export($arr), '</pre>';

PhpFiddle: http://phpfiddle.org/lite/code/un7u-j1pt

PhpFiddle:{{link1:http://phpfiddle.org/lite/code/un7u-j1pt}}

这会进行部分匹配/替换,而不一定是整个值的替换。 - mickmackusa

1

PHP 8,一个严格的版本,用于替换一个字符串值为另一个:

array_map(fn (string $value): string => $value === $find ? $replace : $value, $array);

一个例子 - 将值foo 替换为 bar
array_map(fn (string $value): string => $value === 'foo' ? 'bar' : $value, $array);

我喜欢你的回答,但是设置$find和$replace仍然是一个挑战。传递静态字符串仍然是一个挑战。 - Puneet Sharma

0
你可以通过调用包含字符串开始和结束锚点(^$)的模式来进行完整的字符串匹配,而无需指定符合值的键。如果搜索项可能包含对正则表达式引擎具有特殊含义的字符,则务必使用preg_quote()进行转义以避免出现故障。虽然不是必须要用正则表达式,但正则表达式提供了一些非常方便的方法来调整搜索项处理。(演示
function array_replace_value(&$ar, $value, $replacement)
{
    $ar = preg_replace(
              '/^' . preg_quote($value, '/') . '$/',
              $replacement,
              $ar
          );
}

我可能更倾向于使用带有箭头函数语法的array_map(),以便可以在自定义函数作用域内访问全局变量。(演示)

$needle = 'foo';
$newValue = 'bar';

var_export(
    array_map(fn($v) => $v === $needle ? $newValue : $v, $array)
);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接