85

Is there an easy equivalent to this in JavaScript?

$find = array("<", ">", "\n");
$replace = array("&lt;", "&gt;", "<br/>");

$textarea = str_replace($find, $replace, $textarea); 

This is using PHP's str_replace, which allows you to use an array of words to look for and replace. Can I do something like this using JavaScript / jQuery?

...
var textarea = $(this).val();

// string replace here

$("#output").html(textarea);
...
Ry-
  • 218,210
  • 55
  • 464
  • 476
Tim
  • 6,986
  • 8
  • 38
  • 57
  • 3
    Just for clarification, are you doing this to escape html? – NT3RP Feb 21 '11 at 18:11
  • Multiple replace instead of single replace? If you want to do anything like that efficiently, you need a regular expression. That is not what the selected answer is doing. – HoldOffHunger May 04 '18 at 19:55
  • See this [post](https://stackoverflow.com/a/51242102/7848529), I think it is what you are looking for – aabiro Jul 17 '18 at 22:37

18 Answers18

92

You could extend the String object with your own function that does what you need (useful if there's ever missing functionality):

String.prototype.replaceArray = function(find, replace) {
  var replaceString = this;
  for (var i = 0; i < find.length; i++) {
    replaceString = replaceString.replace(find[i], replace[i]);
  }
  return replaceString;
};

For global replace you could use regex:

String.prototype.replaceArray = function(find, replace) {
  var replaceString = this;
  var regex; 
  for (var i = 0; i < find.length; i++) {
    regex = new RegExp(find[i], "g");
    replaceString = replaceString.replace(regex, replace[i]);
  }
  return replaceString;
};

To use the function it'd be similar to your PHP example:

var textarea = $(this).val();
var find = ["<", ">", "\n"];
var replace = ["&lt;", "&gt;", "<br/>"];
textarea = textarea.replaceArray(find, replace);
Bob
  • 7,851
  • 5
  • 36
  • 48
  • Thanks bob, assuming this is using prototype(?) would you know how to do this using jQuery? – Tim Feb 21 '11 at 21:42
  • 3
    @Tim This is regular JavaScript, no extra library needed. JavaScript is a prototypal language which means every object has a prototype it inherits from. Adding to the object's prototype is simply a way to extend all such objects. – Bob Feb 21 '11 at 23:21
  • How would I then call the function please Bob? Or would I not have to? many thanks :) – Tim Feb 22 '11 at 08:20
  • Bob, regarding this, how do I make it so that the search and replace is global - for every instance of the 'found' matches? Thanks – Tim Feb 27 '11 at 23:04
  • Sorry to keep bugging you, but I'm basically trying to insert html tags where I have custom ones for a simple rich text editor i'm making but using your code I'm still having problems :( Would you mind at all having a look...? http://tiny.cc/f28jq – Tim Feb 28 '11 at 08:18
  • @Tim What are the specific problems are you having? – Bob Mar 02 '11 at 16:05
  • 3
    "tar pit".replaceArray(['tar', 'pit'], ['capitol', 'house']) // "cahouseol house" – Kuroki Kaze Sep 05 '13 at 15:15
  • 6
    This solution doesn't work for the following: String: "The cat hits the dog" find array: ['cat', 'dog'] replace array: ['dog, 'cat'] – derekdreery Apr 17 '14 at 17:03
  • 3
    @derekdreery The function neither work for strings that contains `RegExp` characters, for example: find array ["(", ")"] replace array ["[", "]"] – ElChiniNet Jan 04 '16 at 03:19
  • To allow the function to receive an array or just a string to replace you can use: replaceString = replaceString.replace(regex, typeof(replace)=='object'? replace[i]: replace); – Rafael Moni May 03 '16 at 17:12
  • This is not the correct solution @RyanOHara; see http://stackoverflow.com/a/34560648/445295 or http://stackoverflow.com/a/37949642/445295 for accurate answers. – Stephen M. Harris Jun 21 '16 at 16:21
  • PERFECT! Thank you so much – Luiz Gonçalves Jun 19 '17 at 14:04
  • Recommend to change `replaceString = this;` to `replaceString = this.valueOf();`, otherwise, if `find` is empty, the function will return a string Object instead of string primitive. – Elect2 Mar 13 '19 at 17:48
  • Be careful editing the String prototype. Other libraries or scripts on the page might do the same thing and cause conflicts. – adjwilli Feb 27 '20 at 13:49
54

Common Mistake

Nearly all answers on this page use cumulative replacement and thus suffer the same flaw where replacement strings are themselves subject to replacement. Here are a couple examples where this pattern fails (h/t @KurokiKaze @derekdreery):

function replaceCumulative(str, find, replace) {
  for (var i = 0; i < find.length; i++)
    str = str.replace(new RegExp(find[i],"g"), replace[i]);
  return str;
};

// Fails in some cases:
console.log( replaceCumulative( "tar pit", ['tar','pit'], ['capitol','house'] ) );
console.log( replaceCumulative( "you & me", ['you','me'], ['me','you'] ) );

Solution

function replaceBulk( str, findArray, replaceArray ){
  var i, regex = [], map = {}; 
  for( i=0; i<findArray.length; i++ ){ 
    regex.push( findArray[i].replace(/([-[\]{}()*+?.\\^$|#,])/g,'\\$1') );
    map[findArray[i]] = replaceArray[i]; 
  }
  regex = regex.join('|');
  str = str.replace( new RegExp( regex, 'g' ), function(matched){
    return map[matched];
  });
  return str;
}

// Test:
console.log( replaceBulk( "tar pit", ['tar','pit'], ['capitol','house'] ) );
console.log( replaceBulk( "you & me", ['you','me'], ['me','you'] ) );

Note:

This is a more compatible variation of @elchininet's solution, which uses map() and Array.indexOf() and thus won't work in IE8 and older.

@elchininet's implementation holds truer to PHP's str_replace(), because it also allows strings as find/replace parameters, and will use the first find array match if there are duplicates (my version will use the last). I didn't accept strings in this implementation because that case is already handled by JS's built-in String.replace().

Stephen M. Harris
  • 7,163
  • 3
  • 38
  • 44
  • 4
    @StephenM.Harris Cool answer, you have noticed too that almost all answers in the page are using cumulative replacements. – ElChiniNet Feb 09 '17 at 23:09
  • This doesn't work when replacing characters like brackets. For example, it's common to use ((placeholder)) style tags and this will replace it those ((undefined)) https://jsfiddle.net/oLfmeaa6/1/ – MacroMan Mar 21 '18 at 11:50
  • 3
    @MacroMan fixed! Had to update the regex that escapes special regex chars (which just sounds bug-prone :D). Thanks for pointing this out! – Stephen M. Harris Mar 22 '18 at 06:53
  • Love this code. Addendum: I changed it to replaceBulk(str, obj) {var findArray = Object.keys(obj), var replaceArray = Object.values(obj);....} So, I can pass in a simple hash-object of {"x":"y"...} replacements. Seems easier to maintain. – HoldOffHunger May 05 '18 at 00:53
  • @HoldOffHunger The double array inputs are truer to PHP's `str_replace()` this was intended to emulate -- but that aside I prefer the object input too! Just keep in mind `Object.values` will not work in IE without a polyfill. – Stephen M. Harris May 10 '18 at 14:51
  • Great ! It should be the accepted answer. – Joulss Feb 03 '21 at 11:57
  • Shame it does not work when the value that is changed overlaps. `console.log( replaceBulk( "this is just a test", ['is just','just a'], ['is just','just a'] ) );` should return `this is just a test` (the html being invalid is different problem, that can be fixed afterwards) – Conor Reid Feb 11 '22 at 00:21
25
text = text.replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\n/g, '<br/>');
Ry-
  • 218,210
  • 55
  • 464
  • 476
hsz
  • 148,279
  • 62
  • 259
  • 315
  • 7
    This is not "at once". Basically the same as this "one-liner": text = text.replace(foo); text = text.replace(bar); – Beejor Dec 03 '15 at 20:59
  • 7
    @Beejor To be fair, the accepted answer is not "at once" either, it just hides the subsequent replacements behind a function. – Michael Apr 13 '16 at 23:36
12

A more visual approach:

String.prototype.htmlProtect = function() {
  var replace_map;

  replace_map = {
    '\n': '<br />',
    '<': '&lt;',
    '>': '&gt;'
  };

  return this.replace(/[<>\n]/g, function(match) { // be sure to add every char in the pattern
    return replace_map[match];
  });
};

and this is how you call it:

var myString = "<b>tell me a story, \n<i>bro'</i>";
var myNewString = myString.htmlProtect();

// &lt;b&gt;tell me a story, <br />&lt;i&gt;bro'&lt;/i&gt;
Utopik
  • 3,783
  • 1
  • 21
  • 24
12

You could use the replace method of the String object with a function in the second parameter to avoid replacing a string that was previously replaced:

First Method (using a find and replace Object)

var findreplace = {"<" : "&lt;", ">" : "&gt;", "\n" : "<br/>"};

textarea = textarea.replace(new RegExp("(" + Object.keys(findreplace).map(function(i){return i.replace(/[.?*+^$[\]\\(){}|-]/g, "\\$&")}).join("|") + ")", "g"), function(s){ return findreplace[s]});

jsfiddle

Second method (using two arrays, find and replace)

var find = ["<", ">", "\n"];
var replace = ["&lt;", "&gt;", "<br/>"];

textarea = textarea.replace(new RegExp("(" + find.map(function(i){return i.replace(/[.?*+^$[\]\\(){}|-]/g, "\\$&")}).join("|") + ")", "g"), function(s){ return replace[find.indexOf(s)]});

jsfiddle

Desired function:

function str_replace($f, $r, $s){
   return $s.replace(new RegExp("(" + $f.map(function(i){return i.replace(/[.?*+^$[\]\\(){}|-]/g, "\\$&")}).join("|") + ")", "g"), function(s){ return $r[$f.indexOf(s)]});
}

$textarea = str_replace($find, $replace, $textarea);

EDIT

This function admits a String or an Array as parameters:

function str_replace($f, $r, $s){
    return $s.replace(new RegExp("(" + (typeof($f) === "string" ? $f.replace(/[.?*+^$[\]\\(){}|-]/g, "\\$&") : $f.map(function(i){return i.replace(/[.?*+^$[\]\\(){}|-]/g, "\\$&")}).join("|")) + ")", "g"), typeof($r) === "string" ? $r : typeof($f) === "string" ? $r[0] : function(i){ return $r[$f.indexOf(i)]});
}
ElChiniNet
  • 2,778
  • 2
  • 19
  • 27
  • looks cool, but not work in some cases :( . e.g. {'[0-1]':'NUM'} – Soyoes Jan 27 '16 at 09:10
  • Hi @Soyoes, tell me in what cases it fails and I'll try to fix it. – ElChiniNet Jan 27 '16 at 09:13
  • Hi @Soyoes, I've tested it and it works: [jsfiddle] (https://jsfiddle.net/uxv2u9n0/) – ElChiniNet Jan 27 '16 at 09:24
  • Hi , I tried something like this {'My':'Your', '[0-1]':'NUM'} with str "My name is Peter, Am 19", using the 1st method. – Soyoes Jan 27 '16 at 09:36
  • 1
    This method is to search and replace `Strings` or `Array` of `Strings`. It not works with RegExps, if you want to use a RegExp like a search parameter, you need to parse the find `Array` to convert it into `RegExp`. I'll give you an example in a couple of minutes. – ElChiniNet Jan 27 '16 at 10:25
  • Hi @Soyoes, something like this: [jsfiddle](https://jsfiddle.net/elchininet/ghc226nk/) – ElChiniNet Jan 27 '16 at 10:56
  • Thank you @elchininet, I think it works for most of the cases, and its a pretty cool answer :) – Soyoes Jan 28 '16 at 01:28
7

A simple forEach loop solves this quite well:

let text = 'the red apple and the green ball';
const toStrip = ['red', 'green'];
toStrip.forEach(x => {
   text = text.replace(x, '');
});

console.log(text);
// logs -> the apple and the ball
Jack Dewhurst
  • 349
  • 3
  • 8
6

The top answer is equivalent to doing:

let text = find.reduce((acc, item, i) => {
  const regex = new RegExp(item, "g");
  return acc.replace(regex, replace[i]);
}, textarea);

Given this:

var textarea = $(this).val();
var find = ["<", ">", "\n"];
var replace = ["&lt;", "&gt;", "<br/>"];

In this case, no imperative programming is going on.

5

Using ES6: There are many ways to search for strings and replace in JavaScript. One of them is as follow

const findFor = ['<', '>', '\n'];

const replaceWith = ['&lt;', '&gt;', '<br/>'];

const originalString = '<strong>Hello World</strong> \n Let\'s code';

let modifiedString = originalString;

findFor.forEach( (tag, i) => modifiedString = modifiedString.replace(new RegExp(tag, "g"), replaceWith[i]) )

console.log('Original String: ', originalString);
console.log('Modified String: ', modifiedString);
Niraj Kaushal
  • 1,452
  • 2
  • 13
  • 20
4
String.prototype.replaceArray = function (find, replace) {
    var replaceString = this;
    for (var i = 0; i < find.length; i++) {
        // global replacement
        var pos = replaceString.indexOf(find[i]);
        while (pos > -1) {
            replaceString = replaceString.replace(find[i], replace[i]);
            pos = replaceString.indexOf(find[i]);
        }
    }
    return replaceString;
};

var textT = "Hello world,,,,, hello people.....";
var find = [".",","];
var replace = ['2', '5'];
textT = textT.replaceArray(find, replace);
// result: Hello world55555 hello people22222
ElChiniNet
  • 2,778
  • 2
  • 19
  • 27
4

You might want to look into a JS library called phpJS.

It allows you to use the str_replace function similarly to how you would use it in PHP. There are also plenty more php functions "ported" over to JavaScript.

http://phpjs.org/functions/str_replace:527

Matt R.
  • 2,209
  • 1
  • 17
  • 19
3

const items = {
  '<': '&lt;',
  '>': '&gt;',
  '\n': '<br/>',
}

const re = new RegExp('[' + Object.keys(items).join('') + ']', 'g')

const input = '<foo>\n<bar>'

const output = input.replaceAll(re, key => items[key])

console.log(output)
Alf Eaton
  • 5,226
  • 4
  • 45
  • 50
2

There is no way to do this in one method call, you'll have to either chain calls together, or write a function that manually does what you need.

var s = "<>\n";
s = s.replace("<", "&lt;");
s = s.replace(">", "&gt;");
s = s.replace("\n", "<br/>");
Bryan Kyle
  • 13,361
  • 4
  • 40
  • 45
  • I like it simple. Was looking for a similar function from php. OK, copy-past - but 3 lines - no a whole prototype function. – Sarah Trees Jul 25 '15 at 19:04
2

For the tags, you should be able to just set the content with .text() instead of .html().

Example: http://jsfiddle.net/Phf4u/1/

var textarea = $('textarea').val().replace(/<br\s?\/?>/, '\n');

$("#output").text(textarea);

...or if you just wanted to remove the <br> elements, you could get rid of the .replace(), and temporarily make them DOM elements.

Example: http://jsfiddle.net/Phf4u/2/

var textarea = $('textarea').val();

textarea = $('<div>').html(textarea).find('br').remove().end().html();

$("#output").text(textarea);
user113716
  • 318,772
  • 63
  • 451
  • 440
0

A version with an object as a parameter:

String.prototype.strtr = function (replace) {
    keys = Object.keys(replace);
    result = this;
    for (i = 0; i < keys.length; i++) {
        result = result.replace(keys[i], replace[keys[i]]);
    }
    return result;
}

function htmlspecialchars(str) {
    return String(str).strtr({">": "&gt;", "<": "&lt;", "\n": "<br/>"});
}

// usage
text = "<span>spam</span>";
htmlspecialchars(text);
0

jquery have a solution for that.

var htmlString = $( element).html(); $( element ).text( htmlString );

view here: https://api.jquery.com/html/

0

wrap all this in a function, you can pass both an array and a string

function str_replace(search,replace,subject) {
if(!Array.isArray(search)){
    subject = subject.replace(new RegExp(search, "g"), replace)
}
else{
    search.forEach( (tag, i) => subject = subject.replace(new RegExp(tag, "g"), replace[i]) )
}
return subject;
}
hovo
  • 11
  • 2
0

Just that!

let v = "Test's <<foo>> ((baAr))";
console.log(v);

const r = ['<', '>', 'a', '\\)', '\\(', '\'' ];

for (var i = r.length - 1; i >= 0; i--) {
  v = v.replace((new RegExp(r[i], "gi")), "_");
}

console.log(v);
Cesar Devesa
  • 990
  • 6
  • 14
  • More escapes: const r = ['<', '>', '\\)', '\\(', '\'', ',', '\\.', ';', '`', '"', '#', '/', '\\\\', '=', '\\+', '\\*', '%', '\\$', '\\?', '!', '&', '{', '}', '\\[', '\\]', '~', '\\^', '\\|', ':']; – Cesar Devesa Oct 12 '22 at 14:03
-1

One method would be:

var text = $(this).val();
text = text.replace(/</g, "&lt;").replace(/>/g, "&gt;");
$("#output").html(text);
James Sumners
  • 14,485
  • 10
  • 59
  • 77