php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #47232 str_replace() factors previous replacements into process
Submitted: 2009-01-28 18:56 UTC Modified: 2009-01-29 14:39 UTC
From: michael dot moussa at gmail dot com Assigned:
Status: Not a bug Package: Strings related
PHP Version: 5.2.8 OS: *
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: michael dot moussa at gmail dot com
New email:
PHP Version: OS:

 

 [2009-01-28 18:56 UTC] michael dot moussa at gmail dot com
Description:
------------
When $search and $replace are arrays, str_replace factors previous replacements into the process and produces unexpected input.

Reproduce code:
---------------
<?php
$search = array('A', 'B', 'C', 'D', 'E');
$replace = array('B', 'C', 'D', 'E', 'F');

echo str_replace($search, $replace, 'ABCDE'); 
?>

Expected result:
----------------
Each letter in the string 'ABCDE' should be replaced by the letter that follows it in the alphabet, that is, A should be replaced with B, B should be replaced with C, etc...

The expected result is 'BCDEF'

Actual result:
--------------
The actual result is 'FFFFF'.  The documentation does not indicate that $subject is continuously updated as the process moves along.

A more practical example:

echo str_replace(
	array(" ", "&"),
	array("&nbsp", "&amp;"),
	"Hello & goodbye!"
	);

This should replace "Hello & goodbye!" with "Hello&nbsp;&amp;&nbsp;goodbye!" but it actually results in "Hello&amp;nbsp&amp;&amp;nbspgoodbye!", as the original replacement of " " with "&nbsp;" introduced an additional ampersand.

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2009-01-28 22:47 UTC] jani@php.net
Maybe this is a bit confusing but I do understand it exactly like 
that:
"If search or replace are arrays, their elements are processed first 
to last."

So in: 
a b c d e 
b c d e f

1st pass: b b c d e
2nd pass: c c c d e
3rd pass: d d d d e
4th pass: e e e e e
5th pass: f f f f f

If it did not work like it does, it would not do what it's expected 
to do. Use preg_replace() instead with proper regexps. str_replace() 
is the quick'n' dirty method..

 [2009-01-28 22:50 UTC] jani@php.net
I mistakenly _deleted_ your comment in the manual when I was supposed 
to edit it and add a note about preg_replace() there as well. Sorry 
for the inconvenience, but can you readd it? (that stupid comment 
moderator thing should ask "are you sure" before actually deleting 
stuff..)

 [2009-01-29 04:43 UTC] michael dot moussa at gmail dot com
Jani,

The documentation says "This function returns a string or an array 
with all occurrences of search in subject replaced with the given 
replace value."

Refer to the following example:

$subject = 'A';

echo str_replace( array('A','B','C','D'), array('B','C','D','E'), 
$subject);

The result is 'E'.  If str_replace() is replacing occurrences in 
*$subject*, then how do we end up with 'E' if 'D' doesn't exist in 
$subject?  The result SHOULD be 'B'.  $subject is 'A', so the first 
replacement replaces 'A' with 'B'.  The second replacement, as the 
documentation states, should check for occurrences of 'B' within 
$subject, *NOT* within str_replace('A', 'B', $subject) - and so on.

If this result is not a bug, then the documentation should be updated 
to indicate that subsequent replacements are done on the result of 
the previous replacement operation.

Thanks
 [2009-01-29 14:40 UTC] michael dot moussa at gmail dot com
BTW: I've reposted my comment to the manual as you requested.  I hope it survives this time. :)
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Sat Dec 21 17:01:58 2024 UTC