how to loop add message into string by fetch from object? - javascript

I make my own dictionary, I keep all word in an object. I use by put some content into content variable
and loop for find the word if which word found, should add message.
How I have to do it?
Can I have result like this
Boom is an American company. It wants to make a new plane. The plan is to have a plane in 2023 The plane will(to happen in the future) be supersonic. It will(to happen in the future) fly from London to New York in three hours. The flight(a journey in an aircraft) ticket will(to happen in the future) not be extremely expensive. It will(to happen in the future) cost as much as a standard business class ticket.
mycode
let content = "Boom is an American company. It wants to make a new plane. The plan is to have a plane in 2023 The plane will be supersonic. It will fly from London to New York in three hours. The flight ticket will not be extremely expensive. It will cost as much as a standard business class ticket.";
var myDictionary =
{
will: "to happen in the future",
flight: "a journey in an aircraft",
cost: "the amount of money needed to buy",
particular: "or this and not any other"
}
for(let i in myDictionary) {//each word
for(i=0;/**/)//this word found, such as "will" have to 4 rounds
{
/*loop for find, how many position in this word.
if this word has 2 positions that first loop add my transalate message after the fist position of word and round 2, if more it's have to keep loop until no found this position and out to main loop for find next word
add in the second position.
*/
generate(i);
}
}
function generate(word)
{
let find_position = content.indexOf(word);
console.log(find_position);
let length_of_word = word.length;
let find_position_after_word = find_position + length_of_word;
let transalate_word = getProperty(word);
let output = content.slice(0, find_position_after_word), transalate_word, content.slice(find_position_after_word)].join('');
}
function getProperty(word_for_transalate)
{
return myDictionary[word_for_transalate];
}

Try reduce with replace
var output = Object.keys(myDictionary).reduce( function(a,b,i){
if (i == 1)
{
a = content.replace( new RegExp( a, "gi" ), a + "(" + myDictionary[ a ] + ")" );
}
a = a.replace( new RegExp( b, "gi" ), b + "(" + myDictionary[ b ] + ")" );
return a;
});
Demo
var content = "Boom is an American company. It wants to make a new plane. The plan is to have a plane in 2023 The plane will be supersonic. It will fly from London to New York in three hours. The flight ticket will not be extremely expensive. It will cost as much as a standard business class ticket.";
var myDictionary = {
will: "to happen in the future",
flight: "a journey in an aircraft",
cost: "the amount of money needed to buy",
particular: "or this and not any other"
};
var output = Object.keys(myDictionary).reduce(function(a, b, i) {
if (i == 1) {
a = content.replace(new RegExp(a, "gi"), a + "(" + myDictionary[a] + ")");
}
a = a.replace(new RegExp(b, "gi"), b + "(" + myDictionary[b] + ")");
return a;
});
console.log( output );

Find position of string within your string and append the value of key-value pair next to it within braces.
var a = "Boom is an American company. It wants to make a new plane.";
var obj = {
"wants" : "2",
"is": "one"
}
for(var key in obj) {
let position = a.indexOf(key) + key.length + 1;
a = [a.slice(0, position), '('+obj[key]+')', a.slice(position)].join('');
}
console.log(a)

Related

Words count JavaScript - For Loop

Updated: I realize that in C I initialized the word counter 1. (I've tried to delete the inquiry but I was not allowed) :/
in order to try to learn to code I signed up for CS50 and on PSET2 there's an exercise called "Readability". I'm trying to recreate the program with JavaScript. According to the instructions provided the output of input should be 55 words but I'm getting 54.
My For Loop is iterating over each element of the array and if it finds a space, it will add 1 to the words counter (my guess is that it is not counting the last word because it ends with a ".")
However, my C program code seems to work fine.
JavaScript Code:
let text = "It was a bright cold day in April, and the clocks were striking thirteen. Winston Smith, his chin nuzzled into his breast in an effort to escape the vile wind, slipped quickly through the glass doors of Victory Mansions, though not quickly enough to prevent a swirl of gritty dust from entering along with him."
let words = 0;
let textArray = Array.from(text);
//Words
for (let i = 0; i < textArray.length; i++){
if (textArray[i] == " "){
words ++;
}
}
console.log("Words: " + words);
C Program Code
#include <cs50.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
int main(void)
{
//Ask user for text
string text = get_string("Text: ");
//define variables
int letters = 0;
int words = 1;
int sentences = 0;
//loop to analyze text
for (int i = 0; i < strlen(text); i++)
{
//count letters
if ((text[i] >= 'a' && text[i] <= 'z') || (text[i] >= 'A' && text[i] <= 'Z'))
{
letters++;
}
//count words
else if (text[i] == ' ')
{
words++;
}
//count sentences
else if ((text[i] == '.') || (text[i] == '?') || (text[i] == '!'))
{
sentences++;
}
}
printf("Words: %i\n", words);
//math calculation (third rule)
float l = 100 * ((float) letters / (float) words);
float s = 100 * ((float) sentences / (float) words);
//printf("l: %i\n", (int) round(l));
//printf("s: %i\n", (int) round(s));
//grade index formula
float grade = (0.0588 * l) - (0.296 * s) - 15.8;
if (grade >= 16)
{
printf("Grade 16+\n");
}
else if (grade < 1)
{
printf("Before Grade 1\n");
}
else
{
printf("Grade %i\n", (int) round(grade));
}
}
If there are 4 spaces in a well-formed sentence then there are 5 words. Example:
"I am a boy" - 3 spaces, 4 words
The above is a naive generalization but for simple cases this is true.
So you can maybe initialize words from 1 instead of 0. This is a very naive solution, but will help as a starting step.
let text = "It was a bright cold day in April, and the clocks were striking thirteen. Winston Smith, his chin nuzzled into his breast in an effort to escape the vile wind, slipped quickly through the glass doors of Victory Mansions, though not quickly enough to prevent a swirl of gritty dust from entering along with him."
let words = 1;
let textArray = Array.from(text);
//Words
for (let i = 0; i < textArray.length; i++){
if (textArray[i] == " "){
words ++;
}
}
console.log("Words: " + words);
EDIT
: Your C code initializes words with 1 so that is the offset.
If there is a single space in two text then word should be number of space + 1
e.g hello world so there is only 1 space so number of word will be 2
let text =
"It was a bright cold day in April, and the clocks were striking thirteen. Winston Smith, his chin nuzzled into his breast in an effort to escape the vile wind, slipped quickly through the glass doors of Victory Mansions, though not quickly enough to prevent a swirl of gritty dust from entering along with him.";
const words = Array.from(text).filter((s) => s === " ").length + 1;
console.log("Words: " + words);
You can use regex here /\s+/
let text =
"It was a bright cold day in April, and the clocks were striking thirteen. Winston Smith, his chin nuzzled into his breast in an effort to escape the vile wind, slipped quickly through the glass doors of Victory Mansions, though not quickly enough to prevent a swirl of gritty dust from entering along with him.";
const words = text.split(/\s+/g).length;
console.log("Words: " + words);
What is wrong with this answer? Isn't this simple
let text = "It was a bright cold day in April, and the clocks were striking thirteen. Winston Smith, his chin nuzzled into his breast in an effort to escape the vile wind, slipped quickly through the glass doors of Victory Mansions, though not quickly enough to prevent a swirl of gritty dust from entering along with him."
let words = 0;
// removing special characters and convert to array by space
let wordCount = text.replace(/[^\w\s]/gi, '').split(" ").length;
console.log(wordCount) // 55
The answers are correct, but the point is the initialize.
If the text is empty, the 'words' should be 0.
let text = "It was a bright cold day in April, and the clocks were striking thirteen. Winston Smith, his chin nuzzled into his breast in an effort to escape the vile wind, slipped quickly through the glass doors of Victory Mansions, though not quickly enough to prevent a swirl of gritty dust from entering along with him."
const textArray = Array.from(text);
let words = (textArray.length)? 1 : 0; // set initial value for words.
textArray.forEach(e => {
if (e === " ") words++;
});
console.log("Words: " + words);
And you can use this line to change string to array.
// const textArray = Array.from(text);
const textArray = [ ...text ];

How to make value auto update when input numbers are changed in javascript?

Here is a link to the tip calculator - it's hosted on netlify.
I created a tip calculator using html, scss, javascript. no tutorials used, so I'm pretty proud. It took me waaayyyyy longer than I had planned on, but it's done. needless to say, I am a complete beginner.
In any event, I need some help.
I need to know how to make the numbers auto-update if I input a new dollar amount into the billing input.
For instance, if the bill is $50, and the tip percent is 50% that's a $25 tip Amount. for a total bill of $75 dollars.
But let's say I mistyped the bill, so I go back to put in $60, 50% of $60 is $30. so the total bill amount should auto-update to $90. But I can't figure out how to get all of that to happen instantaneously when I change the dollar amount in the billing input.
I have a feeling that it has something to do with using a "change" event listener. but I don't understand how to best implement it, or if that's even the answer here.
// Upper Box Selections
const tipPercent = document.querySelector(".tip-percent");
const tipSlider = document.querySelector("#tip-slider");
tipSlider.oninput = function () {
billInput = Number(document.querySelector("#bill-amt").value);
tipPercent.innerHTML = this.value + "%";
//Discovered that number input type still returns a string
//You can wrap multiple variables in parenthesis in order to append methods
let tipAmount = document.querySelector(".tip-amount");
// if a variable is referenced but not defined, it will be added to the window element - can now use in second function
tipTotal = Number((billInput * Number(this.value / 100)).toFixed(2));
tipAmount.innerHTML = "$" + tipTotal.toFixed(2);
const billTotal = document.querySelector(".bill-total");
billForSplit = Number(billInput + tipTotal).toFixed(2);
billTotal.innerHTML =
"<strong>$</strong>" + "<strong>" + billForSplit + "</strong>";
};
// Bottom Box Selections
// -Grab slider value
const splitSlider = document.querySelector("#split-slider");
splitSlider.oninput = function () {
// -Grab split person value-split PERSON for 1, people for more than 1
const splitPeople = document.querySelector(".split-people");
if (splitSlider.value <= 1) {
splitPeople.innerHTML = splitSlider.value + " person";
} else {
splitPeople.innerHTML = splitSlider.value + " people";
}
// -grab tip per person value
const splitTip = document.querySelector(".split-tip");
// -grab total bill per person value
const splitTotal = document.querySelector(".split-total");
// - tip per person equals tipTotal / split slider value
splitTip.innerHTML = "$" + (tipTotal / splitSlider.value).toFixed(2);
// -total bill/person = billTotal / splitSlider.value
splitTotal.innerHTML =
"<strong>$</strong>" +
"<strong>" +
(billForSplit / splitSlider.value).toFixed(2) +
"</strong>";
};
https://wonderful-meninsky-e0b1c7.netlify.app/
You should declare the function with a name like calcTotal() which will be run every time there is an input for the bill and tip:
const tipPercent = document.querySelector(".tip-percent");
const tipSlider = document.querySelector("#tip-slider");
function calcTotal() {
billInput = Number(document.querySelector("#bill-amt").value);
tipPercent.innerHTML = this.value + "%";
//Discovered that number input type still returns a string
//You can wrap multiple variables in parenthesis in order to append methods
let tipAmount = document.querySelector(".tip-amount");
// if a variable is referenced but not defined, it will be added to the window element - can now use in second function
tipTotal = Number((billInput * Number(this.value / 100)).toFixed(2));
tipAmount.innerHTML = "$" + tipTotal.toFixed(2);
const billTotal = document.querySelector(".bill-total");
billForSplit = Number(billInput + tipTotal).toFixed(2);
billTotal.innerHTML =
"<strong>$</strong>" + "<strong>" + billForSplit + "</strong>";
};
tipSlider.oninput = calcTotal;
document.querySelector("#bill-amt").oninput = calcTotal;

How can I us a single var for multiple values?

I am trying to get random values, getting random array elements.
The problem that when i generate them, they are the same.
This may be a stupid question, but how can I get a random value for each instance.
my HTML looks like this
Our Array consists of:<br>
<span id="massParts"></span><br><br>
Generating a word from syllables:<br>
<span id="oneWord"></span><br><br>
Generating a sentence from several words<br>
<span id="oneSentence"></span>
What I am trying to achieve is getting a sentence of randomly generated words. I seethe only solution to create multiple words and then putting them together. But this is not the solution for a bigger text.
my script is:
<script>
// creating an array of syllables
var parts = ["ing", "er", "a", "on", "po", "i", "re", "tion"];
var partsAsString = parts.join(', ');
// display syllables array elements
document.getElementById("massParts").innerHTML = partsAsString;
// getting random element from an array
var a = Math.floor(Math.random() * parts.length);
var b = Math.floor(Math.random() * parts.length);
var c = Math.floor(Math.random() * parts.length);
// making a word with one, two and three syllables
var oneSylWord = parts[a];
var twoSylWord = parts[a]+parts[b];
var threeSylWord = parts[a]+parts[b]+parts[c];
//putting three words into an array
var newWord = [oneSylWord, twoSylWord, threeSylWord];
// taking one of those free words fron the new array
var randWord = newWord[Math.floor(Math.random() * newWord.length)];
// display a random 1,2,3 syllable word
document.getElementById("oneWord").innerHTML = randWord;
// generating a sentence
var sentence = randWord + " " + randWord + " " + randWord + ".";
document.getElementById("oneSentence").innerHTML = sentence;
</script>
I understand that I display the same var randWord and that causes the repetition. but how can I avoid using multiple variables for it.
Thank you.
here is a jsfiddle https://jsfiddle.net/2j9jpcoo/
Put the code into a function and call it multiple times to get a (potentially) different value every time it is called:
function getRandomValue(arr);
return arr[Math.floor(Math.random() * arr.length)];
}
var sentence = getRandomValue(newWord) + " " + getRandomValue(newWord) + " " + getRandomValue(newWord) + ".";
Functions allow you to organize and reuse code. From the above link:
Functions are the bread and butter of JavaScript programming. The concept of wrapping a piece of program in a value has many uses. It is a tool to structure larger programs, to reduce repetition, to associate names with subprograms, and to isolate these subprograms from each other.
I liked the following algorithm in generating random numbers, according to this article where it mentions it is even better in performance but to be honest I did not benchmark it but you could check this in jsfiddle demo, just run it and see the benchmark results
// the initial seed
Math.seed = 6;
// in order to work 'Math.seed' must NOT be undefined,
// so in any case, you HAVE to provide a Math.seed
Math.seededRandom = function(max, min) {
max = max || 1;
min = min || 0;
Math.seed = (Math.seed * 9301 + 49297) % 233280;
var rnd = Math.seed / 233280;
return min + rnd * (max - min);
}
I re-organized your code a bit and created some re-usable functions to get a different random word each time. In this case we can skip the variable and use the return value from the function directly:
// creating an array of syllables
var a, b, c, newWord;
var parts = ["ing", "er", "a", "on", "po", "i", "re", "tion", "con", "de", "sta"];
var partsAsString = parts.join(', ');
// display syllables array elements
document.getElementById("massParts").innerHTML = partsAsString;
function shuffleLetters() {
// getting random element from an array
a = Math.floor(Math.random() * parts.length);
b = Math.floor(Math.random() * parts.length);
c = Math.floor(Math.random() * parts.length);
var oneSylWord = parts[a];
var twoSylWord = parts[a]+parts[b];
var threeSylWord = parts[a]+parts[b]+parts[c];
//putting three words into an array
newWord = [oneSylWord, twoSylWord, threeSylWord];
}
function getRandomWord() {
shuffleLetters();
// taking one of those free words fron the new array
return newWord[Math.floor(Math.random() * newWord.length)];
}
// making a word with one, two and three syllables
shuffleLetters();
// display a random 1,2,3 syllable word
document.getElementById("oneWord").innerHTML = getRandomWord();
// generating a sentence
var sentence = getRandomWord() + " " + getRandomWord() + " " + getRandomWord() + ".";
document.getElementById("oneSentence").innerHTML = sentence;

How to prevent a new object of robots from going to the same location as previous robots?

Things you need to know about my Program
I have created a program in JavaScript that executes Robot instruction that you give. per Robot Object.
The robot is inside a rectangle shaped area. It moves with (x,y) points. Such that (0 <= x <= 50) and (0 <= y <= 50)
The instructions are in Strings of continuous of three repeated letters - There are Three letter that represent the movement of the robot
The program runs each letter and moves the robot according to the letter.
If the program finds out the the robot is out of the surface. Then the robot is lost and the coordinates of that particular robot is kept in array of lists called Lost_Robot
My Question:
I don't know how to prevent a new robot from going to the same coordinates that a previous robot got lost (because of out of Rectangle surface).
How can I achieve from preventing another new robot (when I say new Robot, I mean new Robot Object) from jumping to the same location that a previous robot went and got lost.
I have an array of (x,y) of robots that got lost. But how can I use this array from letting a new robot going to this point?
I tried to use for loop that runs the array to see the coordinates, but doesn't do anything.
Also
While your working on my problem, can you also give me few hints on how can I simplify my code yet doing the same functionality, but more efficiently.
=
var orientation = ["N", "E", "S", "W"];
var instruction = ["L", "R", "F"];
var lost_Robot_Scent = [];
// function created for assigning coordinates and an orientation
function Robot_Coordinatation(x, y, orientation) {
// coordinate (x,y) must be located at (0,0) at the initial state of the program
this.x = 0;
this.y = 0;
// orientation assigned
this.orientation = orientation;
// this is printed for the purpose of tidiness
document.write("============================" + "<br />");
// | ( x,y) | e.g(S)
document.write("| ( " + x + ", " + y + " ) | " + orientation + "<br />");
// We have a nested function here that will determine the movement/instruction of the robot
this.Robot_Instruction = function(instruct_The_Robot) {
// We are making sure here that the length of the instruction is less than 100
if (instruct_The_Robot.length <= 100) {
// if...statement - if x & y is bigger than or equal to 0 and smaller than or equal to 50 -> If its true then go inside the if statment.
// Essentiallly, what this statement is actually doing is that its creating the rectangular grid.
if ((x <= 50 && x >= 0) && (y <= 50 && y >= 0)) {
// itterate the array of the instruct_The_Robot
for (var i = 0; i < instruct_The_Robot.length; i++) {
// if any value of instruct_The_Robot is strictly equal to "L", then go inside this if statement. refer to line: 10
if (instruct_The_Robot[i] === instruction[0]) {
// variable Left declared and instantiated with -90°
var Left = -90 + "&#176";
// variable result instantiated with value (x,y) & orientation
var result = " | ( " + x + ", " + y + " ) " + " | " + orientation + " " + Left + "<br />";
// however, if the if...statment at line: 33 is not true, then follow this : if the value of instruct_The_Robot is equal to "R"...
} else if (instruct_The_Robot[i] === instruction[1]) {
// variable Right instantiated with 90°
var Right = 90 + "&#176";
// variable result instantiated
var result = " | ( " + x + ", " + y + " ) " + " | " + orientation + " " + Right + "<br />";
// however, if the if...statment at line: 33 & elseif at line: 39 is not true, then if instruct_The_Robot is equal to "F"...
} else if (instruct_The_Robot[i] === instruction[2]) {
// variable y_Plus_One is instantiated with the current value of y and moves y one point forward
var y_Plus_One = y += 1;
// if the negation of x & y_Plus_One is smaller than 50 and bigger the 0, then...
if (!((x <= 50 && x >= 0) && (y_Plus_One <= 50 && y_Plus_One >= 0))) {
// then print " lost! "
document.write("LOST!" + "<br />");
// & keep the record of the x and y_Plus_One value to the lost_Robot_Scent array
lost_Robot_Scent.push([x, y]);
// and return false - this stops printing "Lost!" more than one times
return false;
// Otherwise, if the above doesn't satisfy, then...
} else {
// variable result instantiated with the updated coordinates (y_Plus_One)
var result = " | ( " + x + ", " + y_Plus_One + " ) " + " | " + orientation + " " + "<br />";
}
}
}
//print the result
document.write(result);
// if none of the if...statement above satisfy, then...
} else {
// variale lost instantiated with "Lost!" message
var lost = "LOST!" + "<br />";
// push the robot to the lost_Robot_Scent
lost_Robot_Scent.push("| ( " + x + ", " + y + " ) " + "<br />");
}
} else {
alert("There is alot of of instructions given. Please make sure that the instruction is less than 100 instructions");
}
}
}
// new Robot object initialised
var one = new Robot_Coordinatation(50, 50, orientation[1]);
one.Robot_Instruction("LRLRLRLRLRLLRRLRLRLLRLLRRLL");
var two = new Robot_Coordinatation(20, 30, orientation[3]);
two.Robot_Instruction("FFFLLFLRLFLRFLRLLLFRL");
var two = new Robot_Coordinatation(30, 7, orientation[3]);
two.Robot_Instruction("FFFFLRLFLRFLRL");
Maintaining lost_Robot_Scent
I can help you with keeping a collection of locations where your robots get lost (your lost_Robot_Scent array). I suggest using a Set instead on an Array. Sets provide O(1) insertion and O(1) lookup. This probably isn't a big deal in this situation, but it's good to know about Set anyway.
The main problem you'll run into is that array equality is pointer equality: for example, [1, 1] === [1, 1] returns false. One workaround is using toString() on the arrays and storing that in the Set. For example:
var lost_Robot_Scent = new Set();
lost_Robot_Scent.add( [1, 1].toString() );
lost_Robot_Scent.has( [1, 1].toString() ); // -> true
lost_Robot_Scent.has( [2, 2].toString() ); // -> false
I don't know if this is the cleanest solution, but it works. If you want to use an Array instead of a Set, just use push instead of add and includes (or indexOf) instead of has, e.g.
var lost_Robot_Scent = [];
lost_Robot_Scent.push( [1, 1].toString() );
lost_Robot_Scent.includes( [1, 1].toString() ); // -> true
lost_Robot_Scent.includes( [2, 2].toString() ); // -> false
If you are worried about performance, you can test these two methods against each other in specific contexts.
Improve The Code
One thing you can do to simplify your code is to lessen the nested if statements. For example, the first if in your Robot_Instruction function could be
if (instruct_The_Robot.length > 100) {
alert("Too many instructions! Please limit to 100."
return;
}
// continue...
Perhaps this is a bit off-topic, but you should only use comments for things are aren't obvious. For example, variable Left declared and instantiated with -90° is unnecessary.
One last thing: you can simplify the "instructions" loop using a switch statement instead of if/else blocks. Or, if you want to make is super-readable, you can use a JavaScript object like so:
var move = {
L: function() {
// turn left
},
R: function() {
// turn right
},
F: function() {
// move forward
},
};
// then, in the "instructions" loop, you can just do
for (var i = 0; i < instruct_The_Robot.length; i++) {
move[ instruct_The_Robot[i] ]();
}
That's a pretty neat trick.
How to prevent a new robots from getting lost in the same places as old robots
Assuming you've fixed your bugs, and robots are moving. When you determine that a robot is moving forward, you have to determine if the new coordinates are already in the lost_Robot_Scent array. You can do this using something like the following:
var robotLostAtSameLocation = false;
for (var i = 0; i < lost_Robot_Scent.length; i++) {
var lostRobotLocation = lost_Robot_Scent[i];
if(lostRobotLocation[0] === x && lostRobotLocation[1] === y) {
robotLostAtSameLocation = true;
break;
}
}
if (robotLostAtSameLocation) {
// whatever you want to do in this case
}
else {
// whatever you want to do in this case
}
Simple optimization
Note that you can get rid of this loop if you change the lost_Robot_Scent array from containing [x,y] to containing something like 'x:y'. So rather than an array that contains other arrays looking like this: [[39,51], [51,15], [-1,11]], it will be an array containing strings looking like: ['39:51', '51:15', '-1:11']. What this buys you is that you can then just say var robotLostAtSameLocation = lost_Robot_Scent.indexOf(x + ':" + y) > -1;
Recommendation
Change var instruction = ["L", "R", "F"]; into something more like var INSTRUCTIONS = {LEFT: 'L', RIGHT: 'R', FORWARD: 'F'};. This turns lines like instruct_The_Robot[i] === instruction[0] into instruct_The_Robot[i] === INSTRUCTIONS.LEFT, improving readability.
Bugs
You are never updating x, y, or orientation. Your robots are never moving. You are only outputting a string.
You are only checking if the y-coordinate is out of bounds. You are forgetting to check if the x-coordinate is out of bounds.
You are pushing [x,y] into the lost_Robot_Scent array on one line, then pushing "| ( " + x + ", " + y + " ) " + "<br />" into the same array on another line. Don't do that. It's hard to reason about a program when it is not consistent.
There may be other issues - I can't take the time to fully digest it at the moment.

Fastest method to replace all instances of a character in a string [duplicate]

This question already has answers here:
How do I replace all occurrences of a string in JavaScript?
(78 answers)
Closed 3 years ago.
The community reviewed whether to reopen this question 1 year ago and left it closed:
Needs details or clarity Add details and clarify the problem by editing this post.
What is the fastest way to replace all instances of a string/character in a string in JavaScript? A while, a for-loop, a regular expression?
The easiest would be to use a regular expression with g flag to replace all instances:
str.replace(/foo/g, "bar")
This will replace all occurrences of foo with bar in the string str. If you just have a string, you can convert it to a RegExp object like this:
var pattern = "foobar",
re = new RegExp(pattern, "g");
Try this replaceAll:
http://dumpsite.com/forum/index.php?topic=4.msg8#msg8
String.prototype.replaceAll = function(str1, str2, ignore)
{
return this.replace(new RegExp(str1.replace(/([\/\,\!\\\^\$\{\}\[\]\(\)\.\*\+\?\|\<\>\-\&])/g,"\\$&"),(ignore?"gi":"g")),(typeof(str2)=="string")?str2.replace(/\$/g,"$$$$"):str2);
}
It is very fast, and it will work for ALL these conditions
that many others fail on:
"x".replaceAll("x", "xyz");
// xyz
"x".replaceAll("", "xyz");
// xyzxxyz
"aA".replaceAll("a", "b", true);
// bb
"Hello???".replaceAll("?", "!");
// Hello!!!
Let me know if you can break it, or you have something better, but make sure it can pass these 4 tests.
var mystring = 'This is a string';
var newString = mystring.replace(/i/g, "a");
newString now is 'Thas as a strang'
Also you can try:
string.split('foo').join('bar');
You can use the following:
newStr = str.replace(/[^a-z0-9]/gi, '_');
or
newStr = str.replace(/[^a-zA-Z0-9]/g, '_');
This is going to replace all the character that are not letter or numbers to ('_'). Simple change the underscore value for whatever you want to replace it.
Use Regex object like this
var regex = new RegExp('"', 'g');
str = str.replace(regex, '\'');
It will replace all occurrence of " into '.
Just thinking about it from a speed issue I believe the case sensitive example provided in the link above would be by far the fastest solution.
var token = "\r\n";
var newToken = " ";
var oldStr = "This is a test\r\nof the emergency broadcasting\r\nsystem.";
newStr = oldStr.split(token).join(newToken);
newStr would be
"This is a test of the emergency broadcast system."
I think the real answer is that it completely depends on what your inputs look like. I created a JsFiddle to try a bunch of these and a couple of my own against various inputs. No matter how I look at the results, I see no clear winner.
RegExp wasn't the fastest in any of the test cases, but it wasn't bad either.
Split/Join approach seems fastest for sparse replacements.
This one I wrote seems fastest for small inputs and dense
replacements:
function replaceAllOneCharAtATime(inSource, inToReplace, inReplaceWith) {
var output="";
var firstReplaceCompareCharacter = inToReplace.charAt(0);
var sourceLength = inSource.length;
var replaceLengthMinusOne = inToReplace.length - 1;
for(var i = 0; i < sourceLength; i++){
var currentCharacter = inSource.charAt(i);
var compareIndex = i;
var replaceIndex = 0;
var sourceCompareCharacter = currentCharacter;
var replaceCompareCharacter = firstReplaceCompareCharacter;
while(true){
if(sourceCompareCharacter != replaceCompareCharacter){
output += currentCharacter;
break;
}
if(replaceIndex >= replaceLengthMinusOne) {
i+=replaceLengthMinusOne;
output += inReplaceWith;
//was a match
break;
}
compareIndex++; replaceIndex++;
if(i >= sourceLength){
// not a match
break;
}
sourceCompareCharacter = inSource.charAt(compareIndex)
replaceCompareCharacter = inToReplace.charAt(replaceIndex);
}
replaceCompareCharacter += currentCharacter;
}
return output;
}
What's the fastest I don't know, but I know what's the most readable - that what's shortest and simplest. Even if it's a little bit slower than other solution it's worth to use.
So use:
"string".replace("a", "b");
"string".replace(/abc?/g, "def");
And enjoy good code instead of faster (well... 1/100000 sec. is not a difference) and ugly one. ;)
I just coded a benchmark and tested the first 3 answers.
It seems that for short strings (<500 characters)
the third most voted answer is faster than the second most voted one.
For long strings (add ".repeat(300)" to the test string) the faster is answer 1 followed by the second and the third.
Note:
The above is true for browsers using v8 engine (chrome/chromium etc).
With firefox (SpiderMonkey engine) the results are totally different
Check for yourselves!!
Firefox with the third solution seems to be
more than 4.5 times faster than Chrome with the first solution... crazy :D
function log(data) {
document.getElementById("log").textContent += data + "\n";
}
benchmark = (() => {
time_function = function(ms, f, num) {
var z;
var t = new Date().getTime();
for (z = 0;
((new Date().getTime() - t) < ms); z++) f(num);
return (z / ms)
} // returns how many times the function was run in "ms" milliseconds.
function benchmark() {
function compare(a, b) {
if (a[1] > b[1]) {
return -1;
}
if (a[1] < b[1]) {
return 1;
}
return 0;
}
// functions
function replace1(s) {
s.replace(/foo/g, "bar")
}
String.prototype.replaceAll2 = function(_f, _r){
var o = this.toString();
var r = '';
var s = o;
var b = 0;
var e = -1;
// if(_c){ _f = _f.toLowerCase(); s = o.toLowerCase(); }
while((e=s.indexOf(_f)) > -1)
{
r += o.substring(b, b+e) + _r;
s = s.substring(e+_f.length, s.length);
b += e+_f.length;
}
// Add Leftover
if(s.length>0){ r+=o.substring(o.length-s.length, o.length); }
// Return New String
return r;
};
String.prototype.replaceAll = function(str1, str2, ignore) {
return this.replace(new RegExp(str1.replace(/([\/\,\!\\\^\$\{\}\[\]\(\)\.\*\+\?\|\<\>\-\&])/g, "\\$&"), (ignore ? "gi" : "g")), (typeof(str2) == "string") ? str2.replace(/\$/g, "$$$$") : str2);
}
function replace2(s) {
s.replaceAll("foo", "bar")
}
function replace3(s) {
s.split('foo').join('bar');
}
function replace4(s) {
s.replaceAll2("foo", "bar")
}
funcs = [
[replace1, 0],
[replace2, 0],
[replace3, 0],
[replace4, 0]
];
funcs.forEach((ff) => {
console.log("Benchmarking: " + ff[0].name);
ff[1] = time_function(2500, ff[0], "foOfoobarBaR barbarfoobarf00".repeat(10));
console.log("Score: " + ff[1]);
})
return funcs.sort(compare);
}
return benchmark;
})()
log("Starting benchmark...\n");
res = benchmark();
console.log("Winner: " + res[0][0].name + " !!!");
count = 1;
res.forEach((r) => {
log((count++) + ". " + r[0].name + " score: " + Math.floor(10000 * r[1] / res[0][1]) / 100 + ((count == 2) ? "% *winner*" : "% speed of winner.") + " (" + Math.round(r[1] * 100) / 100 + ")");
});
log("\nWinner code:\n");
log(res[0][0].toString());
<textarea rows="50" cols="80" style="font-size: 16; resize:none; border: none;" id="log"></textarea>
The test will run for 10s (+2s) as you click the button.
My results (on the same pc):
Chrome/Linux Ubuntu 64:
1. replace1 score: 100% *winner* (766.18)
2. replace4 score: 99.07% speed of winner. (759.11)
3. replace3 score: 68.36% speed of winner. (523.83)
4. replace2 score: 59.35% speed of winner. (454.78)
Firefox/Linux Ubuntu 64
1. replace3 score: 100% *winner* (3480.1)
2. replace1 score: 13.06% speed of winner. (454.83)
3. replace4 score: 9.4% speed of winner. (327.42)
4. replace2 score: 4.81% speed of winner. (167.46)
Nice mess uh?
Took the liberty of adding more test results
Chrome/Windows 10
1. replace1 score: 100% *winner* (742.49)
2. replace4 score: 85.58% speed of winner. (635.44)
3. replace2 score: 54.42% speed of winner. (404.08)
4. replace3 score: 50.06% speed of winner. (371.73)
Firefox/Windows 10
1. replace3 score: 100% *winner* (2645.18)
2. replace1 score: 30.77% speed of winner. (814.18)
3. replace4 score: 22.3% speed of winner. (589.97)
4. replace2 score: 12.51% speed of winner. (331.13)
Edge/Windows 10
1. replace1 score: 100% *winner* (1251.24)
2. replace2 score: 46.63% speed of winner. (583.47)
3. replace3 score: 44.42% speed of winner. (555.92)
4. replace4 score: 20% speed of winner. (250.28)
Chrome on Galaxy Note 4
1. replace4 score: 100% *winner* (99.82)
2. replace1 score: 91.04% speed of winner. (90.88)
3. replace3 score: 70.27% speed of winner. (70.15)
4. replace2 score: 38.25% speed of winner. (38.18)
I tried a number of these suggestions after realizing that an implementation I had written of this probably close to 10 years ago actually didn't work completely (nasty production bug in an long-forgotten system, isn't that always the way?!)... what I noticed is that the ones I tried (I didn't try them all) had the same problem as mine, that is, they wouldn't replace EVERY occurrence, only the first, at least for my test case of getting "test....txt" down to "test.txt" by replacing ".." with "."... maybe I missed so regex situation? But I digress...
So, I rewrote my implementation as follows. It's pretty darned simple, although I suspect not the fastest but I also don't think the difference will matter with modern JS engines, unless you're doing this inside a tight loop of course, but that's always the case for anything...
function replaceSubstring(inSource, inToReplace, inReplaceWith) {
var outString = inSource;
while (true) {
var idx = outString.indexOf(inToReplace);
if (idx == -1) {
break;
}
outString = outString.substring(0, idx) + inReplaceWith +
outString.substring(idx + inToReplace.length);
}
return outString;
}
Hope that helps someone!
// Find, Replace, Case
// i.e "Test to see if this works? (Yes|No)".replaceAll('(Yes|No)', 'Yes!');
// i.e.2 "Test to see if this works? (Yes|No)".replaceAll('(yes|no)', 'Yes!', true);
String.prototype.replaceAll = function(_f, _r, _c){
var o = this.toString();
var r = '';
var s = o;
var b = 0;
var e = -1;
if(_c){ _f = _f.toLowerCase(); s = o.toLowerCase(); }
while((e=s.indexOf(_f)) > -1)
{
r += o.substring(b, b+e) + _r;
s = s.substring(e+_f.length, s.length);
b += e+_f.length;
}
// Add Leftover
if(s.length>0){ r+=o.substring(o.length-s.length, o.length); }
// Return New String
return r;
};
Use the replace() method of the String object.
As mentioned in the selected answer, the /g flag should be used in the regex, in order to replace all instances of the substring in the string.
#Gumbo adding extra answer - user.email.replace(/foo/gi,"bar");
/foo/g - Refers to the all string to replace matching the case sensitive
/foo/gi - Refers to the without case sensitive and replace all For Eg: (Foo, foo, FoO, fOO)
DEMO

Categories

Resources