5

For a custom script parser in PHP I would like to replace some words in a multiline string that contain double and single quotes. However, only the text that is outside the quotes can be replaced.

Many apples are falling from the trees.    
"There's another apple over there!"    
'Seedling apples are an example of "extreme heterozygotes".'

For example, I would like to replace 'apple' with 'pear', but only outside the quote sentences. So in this case only 'apple' inside 'Many apples are falling from the trees' would be targeted.

The above would give the following output:

Many pears are falling from the trees.    
"There's another apple over there!"    
'Seedling apples are an example of "extreme heterozygotes".'

How can I achieve this?

Nick
  • 11,483
  • 8
  • 41
  • 44

4 Answers4

5

This function does the trick:

function str_replace_outside_quotes($replace,$with,$string){
    $result = "";
    $outside = preg_split('/("[^"]*"|\'[^\']*\')/',$string,-1,PREG_SPLIT_DELIM_CAPTURE);
    while ($outside)
        $result .= str_replace($replace,$with,array_shift($outside)).array_shift($outside);
    return $result;
}

How it works It splits by quoted strings but includes these quoted strings, this gives you alternating non-quoted, quoted, non-quoted, quoted etc strings in an array (some of the non-quoted strings may be blank). It then alternates between replacing the word and not replacing, so only non-quoted strings are replaced.

With your example

$text = "Many apples are falling from the trees.    
        \"There's another apple over there!\"    
        'Seedling apples are an example of \"extreme heterozygotes\".'";
$replace = "apples";
$with = "pears";
echo str_replace_outside_quotes($replace,$with,$text);

Output

Many pears are falling from the trees.    
"There's another apple over there!"    
'Seedling apples are an example of "extreme heterozygotes".'
Timm
  • 12,553
  • 4
  • 31
  • 43
  • I couldn't get the regex used in my [first answer](http://stackoverflow.com/revisions/10929115/1) to work reliably, so I created this function instead which does always work. – Timm Jun 08 '12 at 13:28
  • 1
    I tested your script and found a bug. If you have the escaped characters \' or \" in your string it will close early leading to unpredictable results. This regex fixes it /('(?:[^\\\\']+|\\\\(\\\\\\\\)*.)*'|\"(?:[^\\\\\"]+|\\\\(\\\\\\\\)*.)*\")/ . It's not pretty but it works. There must be a more elegant solution but I can't waste more time on this right now. – Dieter Gribnitz Mar 10 '15 at 09:28
  • As Dieter says, the sample code doesn't work for the following : `$test="x('\'y');y(1);console(\"xyz\",xyz); echo "
  • ".$this->str_replace_outside_quotes("y", "z", $test);` BUT using Dieters version does work
  • – user1432181 Apr 14 '21 at 16:33