PHP str_replace 替换自身

6

我需要将字母 a,o,i,e,u 中的每一个替换为 [aoieu]?
我尝试了以下方法:

str_replace(array('a', 'o', 'i', 'e', 'u'), '[aoieu]?', $input);

但是,当我将输入值改为black时,它并没有返回我期望的bl[aoieu]?ck,而是返回了

bl[a[ao[aoi[aoie[aoieu]?]?[aoieu]?]?[aoie[aoieu]?]?[aoieu]?]?[aoi[aoie[aoieu]?]?[aoieu]?]?[aoie[aoieu]?]?[aoieu]?]?ck

如何让它不替换已经替换的内容?

YoYoMa的评论:“显然有些人错过了这个警告@http://us3.php.net/manual/en/function.str-replace.php。注意替换顺序的陷阱,因为str_replace()从左到右替换,当进行多次替换时,它可能会替换先前插入的值。请参见本文档中的示例。其他人已经用可能的解决方案回答了这个问题。这就是为什么问题会出现的原因。” - Peter O.
2
@powtac 目标是“bl[aoieu]?ck”,这是一个很好的问题! - PJ Brunet
7个回答

5
您可以考虑使用正则表达式,或者自己编写一个函数逐个字母遍历字符串。以下是正则表达式解决方案:
preg_replace('/[aoieu]/', '[aoieu]?', $input);

或者您自己编写一个函数(请注意,$search 只能是单个字符或字符数组,而不是字符串 - 您可以使用 strpos 或类似函数来构建一个处理较长字符串的函数):

function safe_replace($search, $replace, $subject) {
  if(!is_array($search)) {
    $search = array($search);
  }
  $result = '';
  $len = strlen($subject);
  for($i = 0; $i < $len; $i++) {
    $c = $subject[$i];
    if(in_array($c, $search)) {
      $c = $replace;
    }
    $result .= $c;
  }
  return $result;
}
//Used like this:
safe_replace(array('a', 'o', 'i', 'e', 'u'), '[aoieu]?', 'black');

正则表达式一个可行。至于第二个,我不喜欢“自己动手”,毕竟它可能会在编码方面出现问题,尤其是在解释性语言中。 - Daniel
你说的问题是什么?性能问题、调试问题、“糟糕的程序员==糟糕的代码”问题还是其他问题? - Emil Vikström
1
当你实现已经实现的东西时,会遇到一些问题——一堆无用的代码。此外,性能问题也是一个难题,非本地代码中的字符串操作速度较慢。 - Daniel
同样的问题在这里。我正在尝试使用该函数,但不确定我应该为第二个变量添加什么,目前是“[aoieu]?” - v3nt

4
我建议避免使用preglike函数,改用strtr()
这个本地化的函数:
- 仅在输入字符串上进行一次遍历, - 不替换替换项,并且 - 找到替换的最长匹配子字符串(当一个限定字符串在另一个限定字符串中找到时)
代码:
$result = strtr($input, array('a' => '[aoieu]?', 
                         'o' => '[aoieu]?', 
                         'i' => '[aoieu]?', 
                         'e' => '[aoieu]?', 
                         'u' => '[aoieu]?'));

3

您可以尝试这个

<?php
$string = 'black';
$pattern = '/([aeiou])/i';
$replacement = '[aeiou]';
echo preg_replace($pattern, $replacement, $string);
?>

3

摘自文档:

替换顺序注意事项

由于 str_replace() 是从左到右进行替换的,因此在进行多次替换时,可能会替换掉先前插入的某个值。


1

你可能可以使用 preg_replace 来处理这个问题(参见 Thax、Emil 等人的回答)。 否则,如果那太复杂了,你可以进行分词:

$token = '{{{}}}';
// replace the temporary value with the final value
str_replace( $token, '[aoieu]?', 
    // replace all occurances of the string with a temporary value.
    str_replace( (array('a', 'o', 'i', 'e', 'u'), $token, $input ) );

0
$input = str_replace(array('a', 'o', 'i', 'e', 'u'),   '~',          $input);
$input = str_replace('~',                              '[aoieu]?',   $input);

1
当输入中有~时会失败。这不是一个健壮的解决方案,原因微不足道。 - Lightness Races in Orbit
在一般情况下,你不可能“找到另一个不出现的模式”。如果你想要断言这一点是最快的,你应该_证明_它! - Lightness Races in Orbit
可能不是最快的方法,但使用像 ¯œ 这样奇怪的字符可能会起到作用。 - Madara's Ghost
有很多关于str_replace和preg_replace的基准测试。请访问http://www.google.com/search?q=str_replace+vs.+preg_replace。 - powtac

0

在这里:

$output = preg_replace('/[aeiou]/', '[aeiou]?', $input);

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