Yet another deep replace function:
<?php
function str_replace_deep( $search, $replace, $subject)
{
$subject = str_replace( $search, $replace, $subject);
foreach ($subject as &$value)
is_array( $value) and $value =str_replace_deep( $search, $replace, $value);
return $subject;
}
?>
str_replace
(PHP 4, PHP 5)
str_replace — Replace all occurrences of the search string with the replacement string
Description
This function returns a string or an array with all occurrences of search in subject replaced with the given replace value.
If you don't need fancy replacing rules (like regular expressions), you should always use this function instead of ereg_replace() or preg_replace().
Parameters
If search and replace are arrays, then str_replace() takes a value from each array and uses them to do search and replace on subject . If replace has fewer values than search , then an empty string is used for the rest of replacement values. If search is an array and replace is a string, then this replacement string is used for every value of search . The converse would not make sense, though.
If search or replace are arrays, their elements are processed first to last.
- search
-
- replace
-
- subject
-
If subject is an array, then the search and replace is performed with every entry of subject , and the return value is an array as well.
- count
-
Note: If passed, this will hold the number of matched and replaced needles.
Return Values
This function returns a string or an array with the replaced values.
ChangeLog
| Version | Description |
|---|---|
| 5.0.0 | The count parameter was added. |
| 4.3.3 | The behaviour of this function changed. In older versions a bug existed when using arrays as both search and replace parameters which caused empty search indexes to be skipped without advancing the internal pointer on the replace array. This has been corrected in PHP 4.3.3, any scripts which relied on this bug should remove empty search values prior to calling this function in order to mimic the original behavior. |
| 4.0.5 | Most parameters can now be an array. |
Examples
Example #1 str_replace() examples
<?php
// Provides: <body text='black'>
$bodytag = str_replace("%body%", "black", "<body text='%body%'>");
// Provides: Hll Wrld f PHP
$vowels = array("a", "e", "i", "o", "u", "A", "E", "I", "O", "U");
$onlyconsonants = str_replace($vowels, "", "Hello World of PHP");
// Provides: You should eat pizza, beer, and ice cream every day
$phrase = "You should eat fruits, vegetables, and fiber every day.";
$healthy = array("fruits", "vegetables", "fiber");
$yummy = array("pizza", "beer", "ice cream");
$newphrase = str_replace($healthy, $yummy, $phrase);
// Use of the count parameter is available as of PHP 5.0.0
$str = str_replace("ll", "", "good golly miss molly!", $count);
echo $count; // 2
// Order of replacement
$str = "Line 1\nLine 2\rLine 3\r\nLine 4\n";
$order = array("\r\n", "\n", "\r");
$replace = '<br />';
// Processes \r\n's first so they aren't converted twice.
$newstr = str_replace($order, $replace, $str);
// Outputs: apearpearle pear
$letters = array('a', 'p');
$fruit = array('apple', 'pear');
$text = 'a p';
$output = str_replace($letters, $fruit, $text);
echo $output;
?>
Notes
Note: This function is binary-safe.
Note: This function is case-sensitive. Use str_ireplace() for case-insensitive replace.
str_replace
23-Jun-2008 07:18
22-Jun-2008 06:16
In response to max's comment on June 20th:
Although I agree with the general statements that you made in your posting, I do at the same time disagree with most of what you wrote.
1) You wrote: Just like "foreach" is slower than "for"
Minor point, but: foreach is NOT slower than for. See:
http://derekgallo.com/2007/04/19/for-vs-foreach/
I ran similar tests myself a while ago, and if memory serves (I posted the results on the company wiki, so I can forget the details after that :-) the tests showed that the foreach did its job in 35% of the time that a regular for loop took. In my mind this was never a surprise (as it apparently is to you, and to the author of aforementioned article), because I'm pretty sure PHP doesn't store its arrays in at consecutive memory addresses, so indexing it through an index (as one would be, using a vanilla for loop) introduces an overhead that an iterator doesn't have.
2) You wrote: expanding pieces of code into simpler, faster routines, general redesign, etc.). The latter one basically turns the code into a mess.
The obvious answer to that is: not if you do it properly. And based on practical experience, I can even say: on the contrary. BECAUSE I spent more time thinking about optimization of code, my simpler, faster code is (much) more tidy than the unoptimized version. If it's not, I refrain from the optimization.
3) You wrote: "Write code for clarity [..] and rather keep the code clearer.
What you wrote seems to amount to a claim that your code is clearer and easier to maintain than mine; if that's true, I would love to read what metrics you used:
- my code is 20% shorter than yours
- your function body has 5 non-empty lines; mine has 6, two of which only contain a curly bracket
- your code uses create_function and array_map, two functions that I'm CONVINCED far fewer PHP programmers use than any of the stuff that I used in my code --you'll no-doubt agree that code complexity is a factor in clarity and maintainability.
Add to all this that
- your code doesn't have any generality that mine lacks
- your code is functionally equivalent to mine
- mine is about 4.5 faster than yours
and I'm pretty sure most programmers would prefer my code over yours. The exception to the rule would of course be the programmers who use create_function just for the fun of having used it.
Please do note that I agree with the general statements that you made, I just don't think they apply in this case.
Cheers!
20-Jun-2008 04:54
In response to jaimthorn's comment on June 20th:
Thanks for pointing out the slow spot, and it's definitely good to have both examples here. Let me elaborate on the "slowness" a bit.
It's a given that any kind of meta-programming technique (evaluating some code within your code, like create_function() does) is always slower than traditional approach, especially in the language which wasn't built with "dynamism" in mind. Just like "foreach" is slower than "for" -- there's always a choice between maintainability (clarity and decoupling of code, declarative style) vs. performance optimization (expanding pieces of code into simpler, faster routines, general redesign, etc.). The latter one basically turns the code into a mess. The best thing to do is to find a common ground. There's an easy way to get balanced - avoid premature optimization. Write code for clarity and conciseness, and only optimize certain parts when they become bottlenecks. IE, if your application only uses interpolation to send out an occasional e-mail - you are unlikely to ever need to optimize interpolate function, and rather keep the code clearer. However, if your application goes through millions of records interpolating them, this difference will be crucial, and a simple code profiling session will point out the bottleneck for you.
Best regards,
Max.
20-Jun-2008 01:52
On the 19th of June, 2008, max at bitsonnet dot com posted a function interpolate that used create_function. I'd never seen create_function before and I thought it was very educational. Thanks, Maxim!
However, the interpolate function can be improved, speed-wise:
<?php
function interpolate2($template, $hash, $prefix = '#{', $postfix = '}')
{
$tmp = array();
foreach($hash as $k => $v)
{
$tmp[$prefix . $k . $postfix] = $v;
}
return str_replace(array_keys($tmp), array_values($tmp), $template);
}
echo interpolate2('Hello, #{username}. Welcome to #{site}.', array('username' => 'World', 'site' => 'php.net'));
?>
According to my own tests, this version is somewhere between 4 and 5 times faster.
Note, btw, that I used a very similar function on the sprintf page.
19-Jun-2008 11:00
I always miss interpolate functionality in PHP, so I wrote this little helper method. It allows you to specify your own markup using $prefix and $postfix.
<?php
# Interpolate a string using hash.
# by Maxim Chernyak ( http://mediumexposure.com )
function interpolate($template, $hash, $prefix = '#{', $postfix = '}' ) {
$tokenize = create_function('$token', 'return "'. $prefix .'".$token."'.$postfix.'";');
$keys = array_keys($hash);
$values = array_values($hash);
$keys = array_map($tokenize, $keys);
return str_replace($keys, $values, $template);
}
?>
For example:
<?php
$result = interpolate('Hello, #{username}. Welcome to #{site}.', array('username' => 'Hakunin', 'site' => 'php.net'));
?>
10-Jun-2008 03:29
in response to griffinmt at charter dot net about a length limit, After some trial and error I've found that this can be worked around using ini_set('memory_limit', 10000000); or whatever sized data you will be dealing with.
11-May-2008 12:59
<?php
function str_clean($str) {
// KG6YPI, Brandon Hansen
// removes extra whitespaces and new lines
// while preserving spaces in words, sentances, etc.
$strip_this=array(" ","\n","\r");
// convert to our own special marker
$str=str_replace($strip_this,"<!ypi!>",$str);
// remove doubles
$str=str_replace("<!ypi!><!ypi!>","",$str);
// convert singles to spaces and trim
$str=trim(str_replace("<!ypi!>"," ",$str));
return $str;
}
?>
09-May-2008 06:27
followup to marc at palaueb dot com str_rreplace
The function replaced the first character of the string if no character was found so I transformed it to check if the caracter exists in the string and to return an unchaged string if it is not there.
function str_rreplace($search,$replace,$subject){
if (strpos($subject,$search) !== false){
$strrpos=strrpos($subject,$search);
return substr_replace($subject,$replace,$strrpos,strlen($search));
}
else{
return $subject;
}
}
28-Apr-2008 12:32
The example presented by bladescope at googlemail dot com has a couple of syntax errors. This works:
<?php
$template = "The {color} {object} is in {location}";
$array = array(
'{object}' => 'Ball',
'{color}' => 'Red',
'{location}' => 'The Playground',
);
foreach ($array as $search => $replace) {
$template = str_replace($search, $replace, $template);
}
print $template;
?>
I did not check it for speed or thoroughly test it, but this function seems to do the same thing more succinctly.
<?php
function template($array, $template) {
return str_replace(
array_keys($array),
array_values($array),
$template
);
}
echo template(
array(
'{color}' => 'red',
'{object}' => 'ball',
'{location}' => 'the playground',
),
'The {color} {object} is in {location}.'
);
?>
16-Apr-2008 04:07
An easier and safer way to use str_replace with arrays without the risk of order messups is by creating an array. The title would be the string to search for, and the value would be the value to replace it with. From there, it's a matter of using a foreach loop. e.g.
<?php
$template = "The {color} {object} is in {location}";
$array = array(
'{object}' => 'Ball';
'{color}' => 'Red';
'{location}' => 'The Playground';
);
foreach ($array as $search=>$replace) {
$string = str_replace($search, $replace, $template);
}
print $string; // Returns "The Red Ball is in The Playground".
?>
02-Feb-2008 11:04
It would appear that there is a length restriction in str_replace. When processing a large string (approx 35k long) and trying to replace some binary data with characters, it stopped replacing at about the 16K boundary.
Have not yet worked out an alternative yet, other than splitting the sting into pieces first.
24-Sep-2007 10:44
I'm searching for a function who replace the last occurrence of a string but I have not found anything.
Check this out:
function str_rreplace($search,$replace,$subject){
$strrpos=strrpos($subject,$search);
return substr_replace($subject,$replace,$strrpos,strlen($search));
}
the only one problem is that do not have a limit to replace, just replace the last occurrence.
09-Aug-2007 09:50
This is the functions I wrote for the problem reported above, str_replace in multi-dimensional arrays. It can work with preg_replace as well.
function array_replace($SEARCH,$REPLACE,$INPUT) {
if (is_array($INPUT) and count($INPUT)<>count($INPUT,1)):
foreach($INPUT as $FAN):
$OUTPUT[]=array_replace($SEARCH,$REPLACE,$FAN);
endforeach;
else:
$OUTPUT=str_replace($SEARCH,$REPLACE,$INPUT);
endif;
return $OUTPUT;
}
09-Aug-2007 09:22
With PHP 4.3.1, at least, str_replace works fine when working with single arrays but mess it all with two or more dimension arrays.
<?php
$subject = array("You should eat this","this","and this every day.");
$search = "this";
$replace = "that";
$new = str_replace($search, $replace, $subject);
print_r($new); // Array ( [0] => You should eat that [1] => that [2] => and that every day. )
echo "<hr />";
$subject = array(array("first", "You should eat this")
,array("second","this")
,array("third", "and this every day."));
$search = "this";
$replace = "that";
$new = str_replace($search, $replace, $subject);
print_r($new); // Array ( [0] => Array [1] => Array [2] => Array )
?>
22-Jul-2007 10:28
In order to replace carriage return characters from form inputs, if everything else fails, you can try:
<?php
$new_text = str_replace(chr(13).chr(10), '_', $original_text);
?>
And in order to show the line feeds in a javascript alert, you can do:
<?php
$new_text = str_replace(chr(13).chr(10), '\n', $original_text);
?>
13-Jun-2007 03:47
Here is a version that allows for empty multidimensional arrays:
function str_replace_array ($search, $replace, $subject) {
if (is_array($subject)) {
foreach ($subject as $id=>$inner_subject) {
$subject[$id]=str_replace_array($search, $replace, $inner_subject);
}
} else {
$subject=str_replace($search, $replace, $subject);
}
return $subject;
}
05-Jun-2007 08:27
I found that having UTF-8 strings in as argument didnt
work for me using heavyraptors function.
Adding UTF-8 as argument on htmlentities
fixed the problem.
cheers, tim at hysniu.com
<?php
function replace_accents($str) {
$str = htmlentities($str, ENT_COMPAT, "UTF-8");
$str = preg_replace(
'/&([a-zA-Z])(uml|acute|grave|circ|tilde);/',
'$1',$str);
return html_entity_decode($str);
}
?>
26-Feb-2007 02:48
My input is MS Excel file but I want to save ‘,’,“,” as ',',",".
$badchr = array(
"\xc2", // prefix 1
"\x80", // prefix 2
"\x98", // single quote opening
"\x99", // single quote closing
"\x8c", // double quote opening
"\x9d" // double quote closing
);
$goodchr = array('', '', '\'', '\'', '"', '"');
str_replace($badchr, $goodchr, $strFromExcelFile);
Works for me.
16-Feb-2007 09:30
This is a more rigid alternative to spectrereturns at creaturestoke dot com's replace_different function:
<?php
function str_replace_many ($search, $replacements, $subject) {
$index = strlen($subject);
$replacements = array_reverse($replacements);
if (count($replacements) != substr_count($subject, $search)) {
return FALSE;
}
foreach ($replacements as $replacement) {
$index = strrpos(substr($subject, 0, $index), $search);
$prefix = substr($subject, 0, $index);
$suffix = substr($subject, $index + 1);
$subject = $prefix . $replacement . $suffix;
}
return $subject;
}
?>
This will return false if there are a different number of $replacements versus number of occurrences of $search in $subject. Additionally, $search much be exactly one character (if a string is provided, only the first character in the string will be used). Examples:
<?php
echo str_replace_many('?',array('Jane','banana'),'? is eating a ?.');
?>
prints: "Jane is eating a banana."
14-Feb-2007 11:56
The function works with arrays (as stated) provided those are unidimensional arrays.
In case you use multidimensional arrays, it won't replace anything, at least in PHP 4.4. If you need to work with multidimensional arrays, you should iterate (using foreach) over every unidimensional array.
Before spending hours searching your application why it makes UTF-8 encoding into some malformed something with str_replace, make sure you save your PHP file in UTF-8 (NO BOM).
This was at least one of my problems.
27-Nov-2006 10:32
I create a little function to transform (to example) "User@example.net" in "user AT example DOT net" and conversely.
<?php
function code_mail($email) {
if(preg_match('`^.+@.+\..{1,5}$`', $email)) { //email format
$email = str_replace('.', ' DOT ', $email); //replace . by dot
$email = str_replace('@', ' AT ', $email); //replace @ by at
return $email;
}
else { //not email format
return false;
}
}
function decode_mail($email) { //on décode...
$email = str_replace(' DOT ', '.', $email); //replace dot by .
$email = str_replace(' AT ', '@', $email); //replace at by @
return $email;
}
?>
11-Nov-2006 12:14
This simple function may be usefull to convert czech text from cp-1250 encoding to iso-8859-2 (convert S, T and Z with caron).
I use it because mbstring does not support windows-1250 (i.e. mb_convert_encoding(win2iso($text), "utf-8", "iso-8859-2");).
<?php
function win2iso($text)
{
$win = array ("\x9A", "\x9D", "\x9E", "\x8A", "\x8D", "\x8E");
$iso = array ("\xB9", "\xBB", "\xBE", "\xA9", "\xAB", "\xAE");
return str_replace($win, $iso, $text);
}
?>
30-Jul-2006 03:50
You may have decided to save in a non ANSI format a file so that a few fancy chars that you plan to replace can be viewed by your human eyes too (aren't all those empty rectangles a curse?).
Fine. All works just fine in the file, and all the replacements occur as intended.
You make a class out of those codes.
Then you put this non ANSI encoded file in your includes folder. Isn't it a nice class?
Well, don't call in such class as an include into another file, if the latter is ANSI : the char look up tables will NOT match, and the latter file (say the caller) will (I guess) feed ANSI codes to the included file (say the called) and you will spend a day wondering why the class methods work 100% well when you perform replacements directly from within the called, and yet the very same methods, even with the very same copied-and-pasted examples, fail miserably when performed from within the caller.
A very "stimulating" debugging!
I just came out from a night spent on this. I just forgot the included class file wasn't saved as an ANSI.
<?php
class regexp{
//blah blah...
var $toascii=array( 'Ã' => 'A');
//blah blah
function toascii_replace($input, $addSlashes=0){
return (!$addSlashes)? strtr($input, $this->toascii): addslashes( strtr($input, $this->toascii) );
}
}
$r=new regexp();
$input='Ã';
print $r->toascii_replace($input);//prints A
?>
Now save that class (remove the print statement too) in a format that isn't ANSI, say UTF-8.
Then do:
<?php
include_once('regexp.php');
$r=new regexp();
$input='Ã';
print $r->toascii_replace($input);//prints... Ã
?>
IDENTICAL codes, different results.
note: the class uses strtr but would happen with all replacing oriented functions, and I can pester all the documentations. Maybe I worked out the wrong reason, but the behaviour occurs.
30-Mar-2006 05:40
As an effort to remove those Word copy and paste smart quotes, I've found that this works with UTF8 encoded strings (where $text in the following example is UTF8). Also the elipsis and em and en dashes are replaced.
There is an "invisible" character after the †for the right side double smart quote that doesn't seem to display here. It is chr(157).
<?php
$find[] = '“'; // left side double smart quote
$find[] = 'â€'; // right side double smart quote
$find[] = '‘'; // left side single smart quote
$find[] = '’'; // right side single smart quote
$find[] = '…'; // elipsis
$find[] = '—'; // em dash
$find[] = '–'; // en dash
$replace[] = '"';
$replace[] = '"';
$replace[] = "'";
$replace[] = "'";
$replace[] = "...";
$replace[] = "-";
$replace[] = "-";
$text = str_replace($find, $replace, $text);
?>
30-Jan-2006 06:57
Suggested code has some drawbacks in the context of many replacement pairs (i am not suggesting that mine has none). The example code you provided:
<?php
return str_replace(
array('Ć', 'ć', 'Ĉ', [...]),
array('Ć', 'ć', 'Ĉ', [...]),
strtoupper($string)
) ;
?>
relies on the fact that visual identation is provided by all replacement elements beeing of the same width, which is hardly ever true in the real world (please correct me if I'm wrong). Another nasty feature is that this code extends to the right with addition of new elements while the solution provided in the earlier post extends in the driection of the natural flow of code, thus, retaining correct code width for all cases. Perhaps you have ommited the fact that I specifically intended suggested code format for cases with many replacement pairs indicated with /* many lines here */ in the previous post?
11-Dec-2004 08:57
A simple function to take out the double line breaks "%0D%0A" from a string made from text being wrapped in a textarea and turn them into single line breaks.
<?php
function remove_extra_linebreaks($string) {
$new_string=urlencode ($string);
$new_string=ereg_replace("%0D", " ", $new_string);
$new_string=urldecode ($new_string);
return $new_string;
}
?>
I use it when taking text from a textarea with wrap="hard" that I'm emailing out on the next page, for instance. Otherwise there's an extra empty line between each line in the emailed text, which looks nasty!
23-Oct-2003 04:38
I got sick of trying to replace just a word, so I decided I would write my own string replacement code. When that code because far to big and a little faulty I decided to use a simple preg_replace:
<?php
/**
* Written by Rowan Lewis of PixelCarnage.com
* $search(string), the string to be searched for
* $replace(string), the string to replace $search
* $subject(string), the string to be searched in
*/
function word_replace($search, $replace, $subject) {
return preg_replace('/[a-zA-Z]+/e', '\'\0\' == \'' . $search . '\' ? \'' . $replace . '\': \'\0\';', $subject);
}
?>
I hope that this code helpes someone!
25-Aug-2003 03:12
Take care with order when using arrays in replacement.
<?php
$match=array("ONE","TWO","THREE");
$replace=array("TWO WORDS","MANY LETTERS","OTHER IDEAS");
$sample="ONE SAMPLE";
echo str_replace($match,$replace,$sample);
?>
It will show: "MANY LETTERS WORDS SAMPLE"
That is, after replacing "ONE" with "TWO WORDS", process follows with next array item and it changes "TWO" with "MANY LETTERS".
27-Jun-2003 01:08
An excellent way of making sure your pages don't contain "invalid entities", IE. Valid HTML is using the following function.
Most forum packages / extensions provide output containing the symbol &, we don't want this!
<?php
function include_safe ($file)
{
$array = file($file);
foreach ($array as $line) {
print str_replace('&', '&', $line);
}
}
?>
The same technique could also be used in conjuntion with htmlmspecialchars or htmlentities.
Having a string for $search and an array for $replace won't work. This is mentioned on the preg_replace() page where it's described as not making sense, but not here.
But one could interpret such a situation and hence implement str_replace so that a signature of (string, array, string) or even (string, array, array) would "work". The result of
<?php
$search = '*';
$replace = range(1,20);
$subject = '{*}';
$result = str_replace($search, $replace, $subject);
?>
could be an array of elements "{1}", "{2}", "{3}" .... In other words it would have the same effect as
<?php
$search = '*';
$replace = range(1,20);
$subject = '{*}';
$result = array();
foreach($replace as $r) {
$result[] = str_replace($search, $r, $subject);
}
?>
I leave more elaborate applications to your imagination :)
The result of a str_replace(string,array,array) would therefore presumably be an array of arrays, with its dimensions indexed by the two arrays passed in. But then there's the question of which is the first dimension and which is the second.
07-Jan-2003 01:32
I was trying to remove newlines from a textarea input (result of failed submission of parent form - JS verification not possible in this situation) to send back to the textarea via javascript (due to the fact that setting the value in the textarea tag does not work) and had a hard time figuring it out.
If anyone cares, try replacing: "%0D%0A" which is how I found it(changed my POST method to GET) and tracked it down in the address bar of my browser. Hope this helps, I sure wish someone else had posted it earlier!
10-Oct-2002 12:26
To use one or two arrays in str_replace,
this appears to be the correct format:
<?php
str_replace(array('1st_current_needle_element', '2nd', '3rd'), array('1st_new_needle_element', '2nd', '3rd'), $haystack)
?>
Example of a single array, which simply removes the characters in the first array:
<?php
$text=str_replace(array('<', '>', '\\', '/', '='), "", $text);
?>
This will delete the chars: < > \ / =
It could also be done by first defining the array(s), like this:
<?php
$targetChars=array('<', '>', '\\', '/', '=');
$text=str_replace($targetChars, "", $text);
?>
