Replace multiple strings at once

2019-01-01 09:25发布

问题:

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);
...

回答1:

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);


回答2:

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().



回答3:

text = text.replace(/</g, \'&lt;\').replace(/>/g, \'&gt;\').replace(/\\n/g, \'<br/>\');


回答4:

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;


回答5:

You could use the replace method of the String object with a function in the second parameter:

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)]});
}


回答6:

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



回答7:

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


回答8:

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/>\");


回答9:

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);


回答10:

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.



回答11:

One method would be:

var text = $(this).val();
text = text.replace(/</g, \"&lt;\").replace(/>/g, \"&gt;\");
$(\"#output\").html(text);


回答12:

I had a case where I had to remove characters from a string and did it like this:

 let badChars = [\'å\', \'ä\', \'ö\'];
 let newName = fileName.split(\"\").filter((chr) => badChars.indexOf(chr) === -1).join(\"\");

Would have been extra neat if strings were inherently character arrays in javascript so that we wouldn\'t have needed those split/join, like newName = fileName.filter((chr) => badChars.indexOf(chr) === -1) but I still think this is neat and readable if you only have to deal with characters and not susbstrings.