phpstringpreg-replacestr-replacestrtr

How to replace multiple substrings without replacing replaced substrings?


Help or assist as to replace in my case in such variants:

$string = "This is simple string";

$search = array (
  "This is simple",
  "string",
  "simple",
  "apple"
);

$replace = array (
  "This is red",
  "apple",
  "false",
  "lemon"
);

$result = str_replace($search, $replace, $string);

Result must be: This is red apple

Not so: This is false apple OR This is red lemon OR This is false red lemon

If, at each replacement, the changed line is cut into some variable and then returned later, the result may be correct. But I do not know this is my option, but I could not realize it.


Solution

  • Use strtr():

    $string = "This is simple string";
    
    $search = array
    (
      "This is simple",
      "string",
      "simple",
      "apple"
    );
    
    $replace = array
    (
      "This is red",
      "apple",
      "false",
      "lemon"
    );
    
    echo strtr($string,array_combine($search, $replace));
    

    Output:

    This is red apple
    

    Important

    I must inform readers that this beautiful function is also a quirky one. If you've never used this function before, I recommend that you read the manual as well as the comments beneath it.

    Importantly for this case (rather, my answer):

    If given two arguments, the second should be an array in the form array('from' => 'to', ...). The return value is a string where all the occurrences of the array keys have been replaced by the corresponding values. The longest keys will be tried first. Once a substring has been replaced, its new value will not be searched again.

    In the OP's coding attempt, the keys ($search) are ordered by descending length. This aligns the functions behavior with what most people would expect to happen.

    However, consider this demonstration where the keys (and their values) are shuffled around slightly:

    Code: (Demo)

    $string="This is simple string";
    $search=[
       "string",  // listed first, translated second, changed to "apple" which becomes "untouchable"
       "apple",  // this never gets a chance
       "simple",  // this never gets a chance
       "This is simple"  // listed last, but translated first and becomes "untouchable"
    ];
    $replace=[
       "apple",
       "lemon",
       "false",
       "This is red"
    ];
    echo strtr($string,array_combine($search, $replace));
    

    You may be surprised to know that this provides the same output: This is red apple