javascript regex help - javascript

I have this complex question from my customer, I can't find a answer on it so now I will try to ask you guys.
The quest is the following:
I think that one rule might be: Dots
which appears immediately after a
number, not counted as sentences. This
means that sentence present in the
"8. marts"and "2.567" is not counted as
word dots. In return, each word dots
may be overlooked (if now a sentence
ends with a number: "Vi kommer kl. 8")
but it's probably after all not quite
as often.
Another might be: If there is one
character (a letter or number)
immediately after a sentence is not a
phrase sentence. That would make that
we avoided counting the sentence
present in the "f.eks.", "bl.a."
and "cand.mag.".
I hope I can be helped here.
My code:
<script>
function word_count(field, count) {
var wordsNumberOverSeven = 0;
var wordsNumber = 0
var contentText = $(\'#lix_word_count\').val();
contentText = contentText.replace(\'?\', \'.\');
contentText = contentText.replace(\'!\', \'.\');
contentText = contentText.replace(\',\', \'\');
contentText = contentText.replace(\';\', \'\');
contentText = contentText.replace(\':\', \'\');
contentText = contentText.replace(\'\n\', \' \').replace(/^\s+|\s+$/g,\'\').replace(/\s\s+/g,\' \');
var matchDots = contentText.split(\'.\').length-1;
var match = contentText.split(\' \');
$.each(match, function(){
if ( this.length > 0 )
wordsNumber += 1;
if ( this.length >= 7 )
{
wordsNumberOverSeven += 1;
}
});
var lixMatWords = wordsNumber / matchDots;
var lixMatLongWords = ( wordsNumberOverSeven * 100 ) / wordsNumber;
var lixMatch = Math.round(( lixMatWords + lixMatLongWords ) *100)/100;
var lixType = \'\';
if ( lixMatch <= 24 )
lixType = \'Lixen i din tekst er \'+ lixMatch +\', dvs. at teksten er meget let at læse.\';
else if ( lixMatch <= 34 )
lixType = \'Lixen i din tekst er \'+ lixMatch +\', dvs. at teksten er let at læse\';
else if ( lixMatch <= 44 )
lixType = \'Lixen i din tekst er \'+ lixMatch +\', dvs. at teksten ligger i midterområdet.\';
else if ( lixMatch <= 54 )
lixType = \'Lixen i din tekst er \'+ lixMatch +\', dvs. at teksten er svær at læse.\';
else
lixType = \'Lixen i din tekst er \'+ lixMatch +\', dvs. at teksten er meget svær at læse.\';
/** alert(lixType +\'\nDots: \'+ matchDots +\'\nWords: \'+ wordsNumber +\'\nLangeord: \'+ wordsNumberOverSeven); **/
alert(lixType);
}
</script>

I think we need to see the rest of the rules, or a few more at least.
Perhaps it would be better to describe what you want to include as a sentence, rather than what to exclude. If you are looking for full sentences, then it might be a period preceded by a non-whitespace character and followed by a space or new line or line feed, or some more complex rule set. It may require more than one regular expression with some other logic to sort the more complex cases.

If you want to split sentences based on that rule, then something like
mySentences.match(/(?:[^.0-9]|[0-9]+\.?|\.[a-z0-9])+(?:\.|$)/ig)
should do it.
You'll have to expand a-z to include accented characters in your language, but that should do it.
It produces the following for your input text.
["I think that one rule might be: Dots which appears immediately after a number, not counted as sentences.",
" This means that sentence present in the \"8. marts\"and \"2.567\" is not counted as word dots.",
" In return, each word dots may be overlooked (if now a sentence ends with a number: \"Vi kommer kl.",
" 8\") but it's probably after all not quite as often.",
"\n\nAnother might be: If there is one character (a letter or number) immediately after a sentence is not a phrase sentence.",
" That would make that we avoided counting the sentence present in the \"f.eks.",
"\", \"bl.a.","\" and \"cand.mag.",
"\"."]
so obviously it has trouble with dots that appear inside quoted sections. You could fix that up by walking and rejoining as long as a sentence ends inside a quoted section.
// Given mySentences defined above, walk counting quote characters.
// You could modify the regexp below if your language tends to use
// a different quoting style, e.g. French-style angle quotes.
for (var i = 0; i < mySentences.length - 1; ++i) {
var quotes = mySentences[i].match(/["\u201c\u201d]/g);
// If there are an odd number of quotes, combine the next sentence
// into this one.
if (quotes && quotes.length % 2) {
// In English, it is common to end the quoted section after the
// closing punctuator: Say "hello."
var next = mySentences[i + 1];
if (/^["\u201c\u201d]/.test(next)) {
mySentences[i] += next.substring(0, 1);
mySentences[i + 1] = next.substring(1);
} else {
mySentences[i] += next;
mySentences.splice(i, 1);
--i; // See if there's more to combine into this sentence.
}
}
}
This kind of stuff is pretty brittle though. If you want to know how it's done by people who specialize in this kind of thing, search for "natural language segmentation."

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

Node-red converting bytes to decimal in function node

Im trying to figure out the scaling of the value i get from a modbus read node, and ended up doing it the hard way. So i need to convert the 4 bytes from the buffer, to decimal value in a function node.
This way i can easily tweak the scaling and modbus parameters manually.
I thought the easiest way would be:
Bytes -> Bits -> (apply different parameters) -> Decimal value -> apply optional scaling
And thats what i tried making, but it does not work and i dont se why. Either it does nothing(outputs NaN), or node-red just stops running. And i have to disable the flow from the node-red files. Then restart the raspberry pi, then manually start node-red again.
var In = msg.buffer;
var i;
var j;
var Bit;
var Bits = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];
var BitVal8 = [128,64,32,16,8,4,2,1]
var BitVal32 = [1,2,4,8,16,32,64,128]
var Negative;
var Out;
//Sjekker om MSB er 1
if (In[0] >= 128)
{
Negative= true;
In[0] -= 128;
}
//Regner ut verdien av hvert bit i et 32 bit word
for (i= 8; i<32;i++)
{
j = i-1;
BitVal32[i]= (BitVal32[j]*2);
}
//Går gjennom alle 4 bytes (0-3)
for (i= 0; i<4; i++)
{
//Går gjennom alle bits (0-7) og legger de inn rett i 32 bit var
for (j=0; j<8; j++)
{
Bit= (j+1)*(i+1)-1;
if ((In[i]/BitVal8[j])>1)
{
In[i]-= BitVal8[j];
Bits[Bit]=1;
}
}
}
//Konverterer 32 bit var til decimal var
for (i = 0; i < 32; i++)
{
if (Bits[i]==1)
{
Out+=BitVal32[i];
}
}
//Hvis MSB var 1, negates tallet
if (Negative)
{
Out= Out*-1;
}
msg.payload = Out;
node.status({fill:"blue",shape:"ring",text:msg.topic + ": " + msg.payload});
return msg;
I used these nodes for a while. But i cant get them to work with certain variables from the modbus unit. Becuse the modbus parameter is different on them.
Read through this page, but its the opposite of what i want to do and i dont understand it well enough to apply it to my situation.
1: A i++ in the j-for loop caused node red to crash sometimes.
2: The formula to calculate which bit it should write to in the 32 bit var was wrong. was (byte+1)*(bit+1)-1, which works at some times not all. New formula is ((Byte+1)*8-8+bit
3: At the verry last for loop, i add the value of each bit to the output signal. But the BitValue variable went from small to big, not big to small (was LE, should be BE)
New and working code:
var In = msg.buffer;
var i;
var j;
var Bit;
var Bits = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];
var BitVal8 = [128,64,32,16,8,4,2,1]
var BitVal32 = [2147483648]
var Negative;
var Out= 0;
//Sjekker om MSB er 1
if (In[0] >= 128)
{
Negative= true;
In[0] -= 128;
}
//Regner ut verdien av hvert bit i et 32 bit word
for (i= 1; i<32;i++)
{
j = i-1;
BitVal32[i]= (BitVal32[j]/2);
}
//Går gjennom alle 4 bytes (0-3)
for (i= 0; i<4; i++)
{
//Går gjennom alle bits (0-7) og legger de inn rett i 32 bit var
for (j=0; j<8; j++)
{
Bit= (((i+1)*8)-8+j);
if ((In[i]/BitVal8[j])>=1)
{
In[i]-= BitVal8[j];
Bits[Bit]=1;
}
}
}
//Konverterer 32 bit var til decimal var
for (i = 0; i < 32; i++)
{
if (Bits[i]==1)
{
Out+=BitVal32[i];
}
}
//Hvis MSB var 1, negates tallet
if (Negative)
{
Out= Out*-1;
}
msg.payload = Out;
node.status({fill:"blue",shape:"ring",text:msg.topic + ": " + msg.payload});
return msg;

Multiply & Round JavaScript issue

I'm writing a simple invoicing solution for our company and have to multiply quantity * rate and round the result to two decimal places.
Quantity: 36.5
Rate: 33.33
My multiplication looks like this:
console.log((36.5 * 33.33).toFixed(2))
which returns
1216.54
when it should actually be
1216.55
I think this is because JavaScript is rounding down instead of up. Any idea how to resolve this?
Thanks!
Function work as it described in ES standart. It doesn't round down (not always).
I skip first 7 steps of algorithm in standard (they are not significant in this case).
variables definition:
f - is number of digits required after dot
x - is number (in our case 1216.5449999)
In brackets I describe what happens and why so.
x is lower then 10^21 so
a) let n be integer for which the exact mathematical value of n ÷ 10^f – x is as close to zero as possible. (n will
be 121654)
(difference will be -0.4999999, with rights rounding (121655) difference will be (0.50000000)).
b) let m be the String consisting of the digits of the decimal representation of n (m is "121654")
c) f != 0 is true so
i) Let k be the number of characters in m.(k = 6)
ii) if k < f (not out case skipping it)
iii) Let a be the first k–f characters of m (a = "1216"), and let b be the remaining f characters of m (m = "54")
iv) Let m = a + "." + b. (m = "1216.54")
return m;
If you still worry about right rounding in your app. then you, probably, should write your own rounding method (also you may try to search npm library for it. I don't know are they exist).
Edit:
Function with right rounding (it's slow but do the trick):
function myToFixed( val, digits_num ){
if( ! digits_num ) digits_num = 0
var tmp = val.toString().split('.')
var decimal = tmp[1]
var full = tmp[0];
var regex = /[5-9]/
var match = regex.exec( decimal.slice( digits_num ) )
if( ! match ){ return val.toFixed( digits_num ) }
var i = match.index + digits_num
while( i >= digits_num ){ val = ( parseFloat( val ).toFixed( i ) ); i-- }
return val.toString()
}

Advice on how to code Luhn Credit Card validation with Javascript?

I'm pretty awful at Javascript as I've just started learning.
I'm doing a Luhn check for a 16-digit credit card.
It's driving me nuts and I'd just appreciate if someone looked over it and could give me some help.
<script>
var creditNum;
var valid = new Boolean(true);
creditNum = prompt("Enter your credit card number: ");
if((creditNum==null)||(creditNum=="")){
valid = false;
alert("Invalid Number!\nThere was no input.");
}else if(creditNum.length!=16){
valid = false;
alert("Invalid Number!\nThe number is the wrong length.");
}
//Luhn check
var c;
var digitOne;
var digitTwo;
var numSum;
for(i=0;i<16;i+2){
c = creditNum.slice(i,i+1);
if(c.length==2){
digitOne = c.slice(0,1);
digitTwo = c.slice(1,2);
numSum = numSum + (digitOne + digitTwo);
}else{
numSum = numSum + c;
}
}
if((numSum%10)!=0){
alert("Invalid Number!");
}else{
alert("Credit Card Accepted!");
}
</script>
The immediate problem in your code is your for loop. i+2 is not a proper third term. From the context, you're looking for i = i + 2, which you can write in shorthand as i += 2.
It seems your algorithm is "take the 16 digits, turn them into 8 pairs, add them together, and see if the sum is divisible by 10". If that's the case, you can massively simplify your loop - you never need to look at the tens' place, just the units' place.
Your loop could look like this and do the same thing:
for (i = 1; i < 16; i +=2) {
numSum += +creditNum[i];
}
Also, note that as long as you're dealing with a string, you don't need to slice anything at all - just use array notation to get each character.
I added a + in front of creditNum. One of the issues with javascript is that it will treat a string as a string, so if you have string "1" and string "3" and add them, you'll concatenate and get "13" instead of 4. The plus sign forces the string to be a number, so you'll get the right result.
The third term of the loop is the only blatant bug I see. I don't actually know the Luhn algorithm, so inferred the rest from the context of your code.
EDIT
Well, it would have helped if you had posted what the Luhn algorithm is. Chances are, if you can at least articulate it, you can help us help you code it.
Here's what you want.
// Luhn check
function luhnCheck(sixteenDigitString) {
var numSum = 0;
var value;
for (var i = 0; i < 16; ++i) {
if (i % 2 == 0) {
value = 2 * sixteenDigitString[i];
if (value >= 10) {
value = (Math.floor(value / 10) + value % 10);
}
} else {
value = +sixteenDigitString[i];
}
numSum += value;
}
return (numSum % 10 == 0);
}
alert(luhnCheck("4111111111111111"));
What this does is go through all the numbers, keeping the even indices as they are, but doubling the odd ones. If the doubling is more than nine, the values of the two digits are added together, as per the algorithm stated in wikipedia.
FIDDLE
Note: the number I tested with isn't my credit card number, but it's a well known number you can use that's known to pass a properly coded Luhn verification.
My below solution will work on AmEx also. I submitted it for a code test a while ago. Hope it helps :)
function validateCard(num){
var oddSum = 0;
var evenSum = 0;
var numToString = num.toString().split("");
for(var i = 0; i < numToString.length; i++){
if(i % 2 === 0){
if(numToString[i] * 2 >= 10){
evenSum += ((numToString[i] * 2) - 9 );
} else {
evenSum += numToString[i] * 2;
}
} else {
oddSum += parseInt(numToString[i]);
}
}
return (oddSum + evenSum) % 10 === 0;
}
console.log(validateCard(41111111111111111));
Enjoy - Mitch from https://spangle.com.au
#Spangle, when you're using even and odd here, you're already considering that index 0 is even? So you're doubling the digits at index 0, 2 and so on and not the second position, fourth and so on.. Is that intentional? It's returning inconsistent validations for some cards here compared with another algorithm I'm using. Try for example AmEx's 378282246310005.

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