Use PHP functions in JavaScript

JavaScript str_replace

Replaces all occurrences of search in haystack with replace

1
2
3
4
56
7
8
9
1011
12
13
14
1516
17
18
19
2021
22
23
24
2526
27
28
29
3031
32
33
34
3536
37
38
39
4041
42
43
44
4546
47
48
49
function str_replace (search, replace, subject, count) {
    // Replaces all occurrences of search in haystack with replace  
    // 
    // version: 1008.1718
    // discuss at: http://phpjs.org/functions/str_replace    // +   original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +   improved by: Gabriel Paderni
    // +   improved by: Philip Peterson
    // +   improved by: Simon Willison (http://simonwillison.net)
    // +    revised by: Jonas Raoni Soares Silva (http://www.jsfromhell.com)    // +   bugfixed by: Anton Ongson
    // +      input by: Onno Marsman
    // +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +    tweaked by: Onno Marsman
    // +      input by: Brett Zamir (http://brett-zamir.me)    // +   bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +   input by: Oleg Eremeev
    // +   improved by: Brett Zamir (http://brett-zamir.me)
    // +   bugfixed by: Oleg Eremeev
    // %          note 1: The count parameter must be passed as a string in order    // %          note 1:  to find a global variable in which the result will be given
    // *     example 1: str_replace(' ', '.', 'Kevin van Zonneveld');
    // *     returns 1: 'Kevin.van.Zonneveld'
    // *     example 2: str_replace(['{name}', 'l'], ['hello', 'm'], '{name}, lars');
    // *     returns 2: 'hemmo, mars'    var i = 0, j = 0, temp = '', repl = '', sl = 0, fl = 0,
            f = [].concat(search),
            r = [].concat(replace),
            s = subject,
            ra = r instanceof Array, sa = s instanceof Array;    s = [].concat(s);
    if (count) {
        this.window[count] = 0;
    }
     for (i=0, sl=s.length; i < sl; i++) {
        if (s[i] === '') {
            continue;
        }
        for (j=0, fl=f.length; j < fl; j++) {            temp = s[i]+'';
            repl = ra ? (r[j] !== undefined ? r[j] : '') : r[0];
            s[i] = (temp).split(f[j]).join(repl);
            if (count && s[i] !== temp) {
                this.window[count] += (temp.length-s[i].length)/f[j].length;}        }
    }
    return sa ? s : s[0];
}
external links: original PHP docs | raw js source

Examples

» Example 1

Running

1
str_replace(' ', '.', 'Kevin van Zonneveld');

Should return

1
'Kevin.van.Zonneveld'

» Example 2

Running

1
str_replace(['{name}', 'l'], ['hello', 'm'], '{name}, lars');

Should return

1
'hemmo, mars'

Dependencies

No dependencies, you can use this function standalone.

Open syntax issues

php.js uses JsLint to help us keep our code consistent and prevent some common bugs.

Eventually we want all code to pass or at least take into consideration most fixes suggested by JsLint, following this JsLint configuration we’ve decided on.


Authors

Thanks to the following developers, you get to have str_replace goodness in JavaScript.

Comments

Add Comment
Use:
[CODE]
your_stuff('here');
[/CODE]
for proper code formatting
By submitting code here you are allowing us to use it in php.js hence dual licensing it under the MIT and GPL licenses

Gravatar
Kevin van Zonneveld
16 Aug '09 Permalink

q  @ Max: It has to do with speed & PHP compliance. Your function will produce different results from PHP's in some cases. Among things, this has to do with Philip's comment from 30 Mar '08

Gravatar
Max
12 Aug '09 Permalink

q  Why do you use such a complicated function?
I have this one in use and it works fine:

function str_replace(search, replace, subject) {
    return subject.split(search).join(replace);
}

Gravatar
Brett Zamir
10 Aug '09 Permalink

q  @Erik: Just use the latest version here now; I recall the code had some buggy behavior, so it was fixed not too long ago.

Gravatar
Erik
10 Aug '09 Permalink

q  One question: JSLint complains about

while (j = 0, i--) {
Problem at line 50 character 17: Expected ')' to match '(' from line 50 and instead saw ','.




Any idea how to fix this and the resulting errors in JSLint? Much appreciated!

Gravatar
Brett Zamir
8 May '09 Permalink

q  Ouch! Thanks! I fixed that, and also had a bug in the next for loop initialization. Ok now in SVN... Thanks again...

Gravatar
Oleg Eremeev
7 May '09 Permalink

q  You forgot to change i-- in for() loop to i++ (or ++i - no difference :) ).

Gravatar
Oleg Eremeev
7 May '09 Permalink

q  I am happy to help you! ;)

Gravatar
Brett Zamir
6 May '09 Permalink

q  @Oleg, as far as why the loop goes down, there is no good reason, except that I was kind of following the pattern that was there previously. :) I changed it to an ascending loop to follow convention and not raise the same question for others. I also optimized the for loops a little by checking for the length at the beginning of the loop instead of upon each iteration. Thanks!

Gravatar
Oleg Eremeev
5 May '09 Permalink

q  Oh, sorry! I have read the documentation on php.net. I thought count param limits count of replaces, but it only counts replaces. I wrote a complete delusion, sorry. :)

Gravatar
Oleg Eremeev
5 May '09 Permalink

q  Ok. Good job, the function is written very correctly. :)
But why:
[...for (i=s.length-1; i >= 0; i--) {...]
not:
[...for (i=0; i <= s.length-1; i++) {...]
??? String-array will be parsed from right to left? I don't know PHP function specification, but I think count param is used to count affected symbols from left to right, it's more useful. Am I right?

Gravatar
Brett Zamir
5 May '09 Permalink

q  See my changes at http://trac.phpjs.org/projects/phpjs/browser/trunk/functions/strings/str_replace.js . I've tested all the PHP examples, and they are all working. Note that count must be in string form, and must out of necessity reference a global.

Gravatar
Oleg Eremeev
4 May '09 Permalink

q  Hi Brett,

My code can convert extra items to empty strings too:[CODE]
function str_replace(search, replace, subject) {
var s = subject;
var f = [].concat(search);
var r = [].concat(replace);
var l = f.length;
var i = 0;

for (i=0; i<l; ++i)
{
s = s.split(f[i]).join((r[i]!=undefined)?r[i]:'');
}

return s;
}
[CODE]But I forgot about count param. It's more difficult. Anyway, I don't want it. :)

Gravatar
Brett Zamir
4 May '09 Permalink

q  Hi Oleg,

Thanks for pointing out the bug... There was also a bug in handling the subject as an array. Should be fixed in SVN now. I think I might have also fixed the comments.

Btw, we can't just use the shorter length since the PHP behavior is to allow a longer search array to have extra items be replaced by the empty string (i.e., the extra items do get replaced (removed)).

I also added the count param...

Gravatar
Oleg Eremeev
4 May '09 Permalink

q  Why Code is uploading not correctly???

Gravatar
Oleg Eremeev
4 May '09 Permalink

q  In previous post something wrong.

function str_replace(search, replace, subject) {
var s = subject;
var f = [].concat(search);
var r = [].concat(replace);
var l = (f.length>r.length) ? r.length : f.length;
var i = 0;

for (i=0; i<l; ++i)
{
	s = s.split(f[i]).join(r[i]);
}

return s;
}

Gravatar
Oleg Eremeev
4 May '09 Permalink

q   Hello. I downloaded yesterday php.full.js. Library is very good, thank you for proceeding. But I tried to use str_replace function. It works not properly. Function replaces all items of search array with first item of replace array found in subject string. I wrote modified function:

function str_replace(search, replace, subject) {
    var s = subject;
    var f = [].concat(search);
    var r = [].concat(replace);
    var l = (f.length>r.length) ? r.length : f.length;
    var i = 0;
	
    for (i=0; i<l; ++i)
    {
        s = s.split(f[i]).join(r[i]);
    }
	
    return s;
}



This one do all I want. I hope it is useful, but I am not sure is it correct.

Sorry for my bad English, I am schoolboy from Latvia.

Gravatar
Kevin van Zonneveld
21 Feb '09 Permalink

q  @ avel: Be sure to checkout http://phpjs.org, I'm making some progress there.

Gravatar
avel
20 Feb '09 Permalink

q  Thanks a lot for this blog. Is really usefull.

i'm from Barcelona and i'm a baby php programer and this php.js library look like so good.

note: my website is nearly in net.

Gravatar
jonze
30 Jan '09 Permalink

q  hello and congratulations for this article(and script also). I needed something like str_replace from php very fast done with javscript and seems that your script does that very well!

Regards!

Gravatar
Brett Zamir
22 Jan '09 Permalink

q  acimeha, yes, using the native JavaScript replace works fine for most cases, but this project aims to support PHP's behavior, which also allows arrays as inputs.

Gravatar
acimeha
22 Jan '09 Permalink

q  hi there !
consider this as solution for str_replace

str = str.replace(new RegExp(&quot;\n\r&quot;, 'gi'), &quot;\n&quot;);


best regards

Gravatar
Kevin van Zonneveld
1 Dec '08 Permalink

q  @ Onno Marsman &amp; T. Wild: It's not my preferred coding style either, we may need to refactor it some day so it will be more consistent to other code found in php.js

Gravatar
Onno Marsman
27 Nov '08 Permalink

q  No trouble at all! I guess you've misunderstood me. Like I said I also don't like that whole shorthand stuff. It's very hard to read indeed.

Gravatar
T.Wild
26 Nov '08 Permalink

q  IN REPLY TO Onno Marsman.
As I said 'I'm not the best JavaScript programmer in the world.' and what I submitted worked for me (well, almost, r+='' should have been r = r+'' etc) in my limited tests, and I was having trouble seeing what the original code was doing anyway - I don't particularly like the shorthand ways of writing ifs etc - that's why I converted s,r and f to strings to be sure.

Your code fix works fine and sorry for the trouble.

Gravatar
Onno Marsman
26 Nov '08 Permalink

q  To be clear: I've only changed the s[i] to (s[i]+'') in that line.

Gravatar
Onno Marsman
26 Nov '08 Permalink

q  T.Wild: I don't have time for testing right now but doesn't the following do the trick a bit better?
When you do pass an array you'd also want every element to be a string.
I don't see any need to convert r to string(s), but I could be wrong. I find the code a bit hard to read.
Why the whole variable name replacement thing anyway? I thought we have a compiler to do this. This only results in more code after compilation.


[CODE=&quot;Javascript&quot;]
while (s[i] = (s[i]+'').split(f[j]).join(ra ? r[j] || &quot;&quot; : r[0]), ++j in f){};
[/CODE]

Gravatar
T.Wild
26 Nov '08 Permalink

q  OOPS, I leaped before I looked at the code properly, this may be a better idea but I'm not the best JavaScript programmer in the world.
[CODE=&quot;Javascript&quot;]
var f = search, r = replace, s = subject;

var ra = r instanceof Array, sa = s instanceof Array, f = [].concat(f), r = [].concat(r), i = (s = [].concat(s)).length;

if(!ra){r+='';}
if(!sa){s+='';}
if(!(f instanceof Array)){f+='';}
[/CODE]

Gravatar
T.Wild
26 Nov '08 Permalink

q  I think the following line should should probably be changed from:
[CODE=&quot;Javascript&quot;]
var f = search, r = replace, s = subject;
[/CODE]
TO
[CODE=&quot;Javascript&quot;]
var f = search+'', r = replace+'', s = subject+'';
[/CODE]

Found this problem (if anyone is interested) when trying:
[CODE=&quot;Javascript&quot;]
str_replace(&quot;foo&quot;,&quot;baa&quot;,location);
//You get the same problem with
str_replace(34,9,123456);
[/CODE]

Gravatar
Kevin van Zonneveld
29 Sep '08 Permalink

q  @ Onno &amp; Anton: Both excellent points. Function updated. Thank you!

Gravatar
Onno Marsman
25 Sep '08 Permalink

q  Why be dependant on is_array when you could just use &quot;instanceof Array&quot; ? This probably saves a bit of performance too.

Gravatar
Anton Ongsono
25 Sep '08 Permalink

q  i have try to use this, but i five me error in FF 2.0.0.16 :
[CODE=&quot;text&quot;]
s[i] has no properties
[Break on this error] while (s[i] = s[i].split(f[j])....in(ra ? r[j] || &quot;&quot; : r[0]), ++j in f){};
[/CODE]
so that i tried to fixed like this :
[CODE=&quot;Javascript&quot;]
function str_replace(search, replace, subject) {
var f = search, r = replace, s = subject;
var ra = is_array(r), sa = is_array(s), f = [].concat(f), r = [].concat(r), i = (s = [].concat(s)).length;

while (j = 0, i--) {
if (s[i])
{
while (s[i] = s[i].split(f[j]).join(ra ? r[j] || &quot;&quot; : r[0]), ++j in f){};
};
};

return sa ? s : s[0];
}
[/CODE]

Gravatar
Anton Ongsono
25 Sep '08 Permalink

q  i have try to use this, but i five me error in FF 2 :
[CODE=&quot;text&quot;]
s[i] has no properties
[Break on this error] while (s[i] = s[i].split(f[j])....in(ra ? r[j] || &quot;&quot; : r[0]), ++j in f){};
[/CODE]

so that i tried to fixed like this :
[CODE=&quot;Javascript&quot;]
function str_replace(search, replace, subject) {
var f = search, r = replace, s = subject;
var ra = is_array(r), sa = is_array(s), f = [].concat(f), r = [].concat(r), i = (s = [].concat(s)).length;

while (j = 0, i--) {
if (s[i])
{
while (s[i] = s[i].split(f[j]).join(ra ? r[j] || &quot;&quot; : r[0]), ++j in f){};
}
};

return sa ? s : s[0];
}
[/CODE]

Gravatar
Kevin van Zonneveld
18 Apr '08 Permalink

q  @ Jonas Raoni: That's astonishing :D The non-overlapping approach was convincing enough for me not to take the effort to test if this was the actual mechanism of PHP. It would make sense though right? Anyway, I will reinstate your version Jonas Raoni, and adjust the test case. Thanks for all of your work! You too Peter, some functions come easy, some tend to be a little of a pain. But that's the challenge &amp; learning experience, right.

Gravatar
Philip
18 Apr '08 Permalink

q  That is incredibly weird... I was certain that PHP replaced all the stuff at once so as not to create overlap... ah well, I guess it's not like that after all. It was a cool function though :P

Gravatar
Jonas Raoni
18 Apr '08 Permalink

q  I didn't looked the comments before, I just saw the code was long and made a version :)~

But it's strange... What php version are you using? The following code, on php 5, gave me as output &quot;hemmo, mars&quot;:

echo str_replace(array('{name}', 'l'), array('hello', 'm'), '{name}, lars');

Gravatar
Philip Peterson
18 Apr '08 Permalink

q  Woah, I didn't see comments #16 or #15... hmm, I'm surprised, it definitely has merit, though...

Gravatar
Philip Peterson
18 Apr '08 Permalink

q  Wow... bravo is all I can say... that's more than 20x faster than my code, too, lol...

Gravatar
Kevin van Zonneveld
17 Apr '08 Permalink

q  @ Jonas Raoni: I've updated, committed, generated, deployed, tested, reverted, commited, generated &amp; deployed ;)

And srry dude but your str_replace did not survive Peter's testcase:
[CODE=&quot;Javascript&quot;]
// should return: hello, mars
str_replace(['{name}', 'l'], ['hello', 'm'], '{name}, lars');
[/CODE]

More info in the comments here.
Guess I'll be needing those medals back ;) nah just kidding :)

Gravatar
Kevin van Zonneveld
17 Apr '08 Permalink

q  @ Jonas Raoni: That looks very promising :) I still have to test it but if you have reduced our function to this, preserving all of it's functionality, then you deserve 3 medals ;)

Gravatar
Jonas Raoni
17 Apr '08 Permalink

q  I just made this code, it's using the already present is_array function.

function str_replace(f, r, s){
var ra = is_array(r), sa = is_array(s), f = [].concat(f), r = [].concat(r), i = (s = [].concat(s)).length;
while(j = 0, i--)
while(s[i] = s[i].split(f[j]).join(ra ? r[j] || &quot;&quot; : r[0]), ++j in f);
return sa ? s : s[0];
}

Example:

alert(str_replace([&quot;a&quot;, &quot;fb&quot;, &quot;c&quot;], [&quot;f&quot;, &quot;g&quot;], [&quot;abcd&quot;]));

Gravatar
Kevin van Zonneveld
15 Apr '08 Permalink

q  @ Philip Peterson: If you like you can now do this in SVN ;)

Gravatar
Philip Peterson
15 Apr '08 Permalink

q  Hmm, I actually can see where that could come in useful though...

[CODE=&quot;Javascript&quot;]

nsub = nsub.replace(new RegExp(__regexp_escape(search[x]), &quot;g&quot;), &quot;[cod&quot;+fincods[x]+&quot;]&quot;);

could work with

nsub = nsub.split(search[x]).join(&quot;[cod&quot;+fincods[x]+&quot;]&quot;);
[/CODE]

and that sort of thing occurs in four places, so there's a significant drop in size, and you probably can even drop that __regexp_escape function [sorry Simon :(]. You probably should keep him in the credits though, even if you take the function out.

Gravatar
Kevin van Zonneveld
13 Apr '08 Permalink

q  @ Jonas Raoni: Hi there, how have you been? Thats a brutal approach :) However the long code we have now supports some features that your approach does not. For more information see the comments here. Thanks for this insightful way though!

Gravatar
Jonas Raoni
12 Apr '08 Permalink

q  For the str_replace the best and fastest method I know it's:

&quot;Jonas Raoni&quot;.split(&quot;a&quot;).join(&quot;X&quot;);

Gravatar
Kevin van Zonneveld
31 Mar '08 Permalink

q  @ Philip: Cool, I've included Simon as well. Thanks again.

Gravatar
Philip
31 Mar '08 Permalink

q  No problem!

Also: Credits to Simon Willison (http://simonwillison.net/2006/Jan/20/escape/) for the regexp_escape function.

Gravatar
Kevin van Zonneveld
31 Mar '08 Permalink

q  @ Philip: A seemingly straightforward function like str_replace turns out to be more complex than e.g. mktime :) I've indented your code and included the extra function (had to 'var' it for namespacing compatibility) in str_replace.

Thanks A LOT for seriously improving this function!

Gravatar
Philip
31 Mar '08 Permalink

q  Not necessarily; what if a result produced by the replacement of one of the shorter strings produced the values of one of the longer searches? Here's a code that works, but I haven't indented the part that I made yet, or commented it, and it requires a second external function... I dunno if you can fix that or not.



[CODE=&quot;Javascript&quot;]
// http://kevin.vanzonneveld.net
// + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
// + improved by: Gabriel Paderni
// + improved by: Philip Peterson
// * example 1: str_replace(' ', '.', 'Kevin van Zonneveld');
// * returns 1: 'Kevin.van.Zonneveld'

function regexp_escape(text) {
if (!arguments.callee.sRE) {
var specials = [
'/', '.', '*', '+', '?', '|',
'(', ')', '[', ']', '{', '}', '\\'
];
arguments.callee.sRE = new RegExp(
'(\\' + specials.join('|\\') + ')', 'g'
);
}
return text.replace(arguments.callee.sRE, '\\$1');
}

function str_replace(search, replace, subject)
{

if(!(replace instanceof Array)){
replace=new Array(replace);
if(search instanceof Array){//If search is an array and replace is a string, then

this replacement string is used for every value of search
while(search.length&gt;replace.length){
replace[replace.length]=replace[0];
}
}
}

if(!(search instanceof Array))search=new Array(search);
while(search.length&gt;replace.length){//If replace has fewer values than search , then an

empty string is used for the rest of replacement values
replace[replace.length]='';
}

if(subject instanceof Array){//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.
for(k in subject){
subject[k]=str_replace(search,replace,subject[k]);
}
return subject;
}




numreplx=search.length;
numon=0;
fincods=new Array();
while(fincods.length&lt;numreplx)
{
nsub=subject;
for(x=0;x&lt;fincods.length;x++)
{
nsub=nsub.replace(new RegExp(regexp_escape(search[x]), &quot;g&quot;), &quot;[cod&quot;+fincods[x]+&quot;]&quot;);
}
for(x=0;x&lt;fincods.length;x++)
{
nsub=nsub.replace(new RegExp(regexp_escape(&quot;[cod&quot;+fincods[x]+&quot;]&quot;), &quot;g&quot;), replace[x]);
}
if(nsub.indexOf(&quot;[cod&quot;+numon+&quot;]&quot;) == -1)
{
fincods[fincods.length]=numon;
}
numon++;
}
for(x=0;x&lt;fincods.length;x++)
{
subject=subject.replace(new RegExp(regexp_escape(search[x]), &quot;g&quot;), &quot;[cod&quot;+fincods[x]+&quot;]&quot;);
}
for(x=0;x&lt;fincods.length;x++)
{
subject=subject.replace(new RegExp(regexp_escape(&quot;[cod&quot;+fincods[x]+&quot;]&quot;), &quot;g&quot;), replace[x]);
}
return subject;
}[/CODE]

Gravatar
Kevin van Zonneveld
31 Mar '08 Permalink

q  @ Philip: Thanks for noticing. My first thought is to order the search array by length, ascending. This way 'l' will be searched &amp; replaced before hello will be.
Do you agree that that would solve the issue?

Gravatar
Philip
30 Mar '08 Permalink

q  There's only a slight problem with this code... in PHP, each entry is replaced all at once, rather than one after another. This creates a problem in the following example:

[CODE=&quot;Javascript&quot;]
function parseInf(kyl){

kyl=str_replace([
&quot;{name}&quot;,
&quot;l&quot;
],
[
&quot;hello&quot;,
&quot;m&quot;
],
kyl);


nev=kyl.split(/\r{0,1}\n-\r{0,1}\n/);


return nev;


}

alert(parseInf(&quot;{name}, lars&quot;));
[/CODE]

Theoretically, the code should return &quot;hello, mars&quot;, but instead it returns &quot;hemmo, mars&quot;. It completes the first iteration before the second, rather than all at once.


Contribute a New function