I need to create some logic that allows for validation of a specified IP range. Not a single IP address but two addresses that make up a single range.
I thought this would be somewhat simple so I devised some JS code that splits up the two input strings represented the ranges using a . delimiter and then compared each number in the first range with the equivalent number in the second range. If the start number is greater than the end number then the range would be invalid.
This works, to a degree. However it's not completely accurate as I'm getting pairs such as 127.0.0.3 / 128.0.0.1 which return false when in reality this pair of IP addresses is a valid range (ignoring the technicalities with using 127 etc.)
I'm not sure how exactly to check for a valid IP range, using Google doesn't seem to return any information on how to validate an IP range either.
How can I change my code around so that all invalid ranges are included and all invalid are excluded?
getIpRangeValidStates() : boolean[] {
console.log("getIdRangeValidStates");
let validStates = [];
for(let i = 0; i < this.ipRangeFormArray.length; i++){
let currentFormGroup = this.ipRangeFormArray.controls[i];
let startRangeElements = (currentFormGroup.get('startRange').value as string).split(".");
let endRangeElements = (currentFormGroup.get('endRange').value as string).split(".");
let rangeValid = true;
for(let j = 0; j < 4; j++) {
let startRangeAsInt = parseInt(startRangeElements[j]);
let endRangeAsInt = parseInt(endRangeElements[j]);
console.log(startRangeAsInt, " : ", endRangeAsInt);
if(isNaN(startRangeAsInt) || isNaN(endRangeAsInt))
{
console.log("NaN, invalid");
rangeValid = false;
}
else
{
if(startRangeAsInt > endRangeAsInt) {
console.log(startRangeAsInt, " > ", endRangeAsInt, "- invalid")
rangeValid = false;
}
}
}
rangeValid === false ? validStates.push(false) : validStates.push(true);
}
console.log("Range states: ", validStates);
return validStates;
}
I split your code in two loops: one that checks if the single elements are valid and one that validates the ranges.
Note that as soon as one of the elements in the first range is larger than its counterpart in the second range we can say that the range is invalid: there is no need to check further. Conversely, if the element in the first range is smaller that the element in the second range then the range is valid. There is really no need to check further unless the elements in both ranges are equal.
getIpRangeValidStates() : boolean[] {
console.log("getIdRangeValidStates");
let validStates = [];
for(let i = 0; i < this.ipRangeFormArray.length; i++){
let currentFormGroup = this.ipRangeFormArray.controls[i];
let startRangeElements = (currentFormGroup.get('startRange').value as string).split(".");
let endRangeElements = (currentFormGroup.get('endRange').value as string).split(".");
let rangeValid = true;
for(let j = 0; j < 4; j++) {
let startRangeAsInt = parseInt(startRangeElements[j]);
let endRangeAsInt = parseInt(endRangeElements[j]);
console.log(startRangeAsInt, " : ", endRangeAsInt);
if(isNaN(startRangeAsInt) || isNaN(endRangeAsInt))
{
console.log("NaN, invalid");
rangeValid = false;
break;
}
}
if (rangeValid) {
for(let j = 0; j < 4; j++) {
let startRangeAsInt = parseInt(startRangeElements[j]);
let endRangeAsInt = parseInt(endRangeElements[j]);
if(startRangeAsInt > endRangeAsInt) {
console.log(startRangeAsInt, " > ", endRangeAsInt, "- invalid");
rangeValid = false;
break;
}
if(startRangeAsInt < endRangeAsInt) {
console.log(startRangeAsInt, " < ", endRangeAsInt, "- valid");
break;
}
}
}
rangeValid === false ? validStates.push(false) : validStates.push(true);
}
console.log("Range states: ", validStates);
return validStates;
}
Of course, this can be simplified, but it will give you the idea.
When working with IPs i would recommend converting the IP to a number instead of using the string representation.
(An IP String is just a nice human-readable 4 byte integer, each block denoting the value of the byte at that position)
Once you have the ip in number form, checking if an ip comes after another is a simple <.
Also checking if an ip is within a certain range start, end is trivial:
ip >= start && ip <= end.
Code Example to convert the ip string into an integer and comparing it:
function ipToNumber(ipStr) {
let [a, b, c, d] = ipStr.split('.').map(Number);
// Note: Normally you would use shifts (a << 24), etc...
// but javascript only supports *signed* 32bit shifts, so we need to use this.
return (a * 2**24) + (b << 16) + (c << 8) + d;
}
let start = ipToNumber("127.0.0.1");
let end = ipToNumber("128.0.0.1");
console.log("Start: ", start.toString(16)); // 0x7f000001
console.log("End: ", end.toString(16)); // 0x80000001
console.log(start > end, start < end); // false, true
// check if ip is in range
let sample1 = ipToNumber("127.244.32.1");
console.log("sample1 in range:", sample1 >= start && sample1 <= end); // true
let sample2 = ipToNumber("128.1.0.22");
console.log("sample2 in range:", sample2 >= start && sample2 <= end); // false
Integrated in your code example it could look like this:
(Note: my typescript isn't very good, i converted it to javascript)
function toIpNumber(ipStr) {
let parts = ipStr.split('.').map(Number);
if(parts.length !== 4 || parts.some(e => isNaN(e) || e < 0 || e > 255)) return false;
let [a,b,c,d] = parts;
return (a * 2**24) + (b << 16) + (c << 8) + d;
}
function getIpRangeValidStates() {
console.log("getIdRangeValidStates");
let validStates = [];
for(let i = 0; i < this.ipRangeFormArray.length; i++){
let currentFormGroup = this.ipRangeFormArray.controls[i];
let startRange = toIpNumber(currentFormGroup.get('startRange').value);
let endRange = toIpNumber(currentFormGroup.get('endRange').value);
let rangeValid = true;
if(startRange === false || endRange === false)
validStates.push(false);
else
validStates.push(startRange <= endRange);
}
console.log("Range states: ", validStates);
return validStates;
}
If i Understood your problem.
The best way to check the provided ips are a range is by converting both ip's to a long int and compare the long int's.
Converting to int can be done like
const d = dottedDec.split('.');
const longInt = ((((((+d[0])*256)+(+d[1]))*256)+(+d[2]))*256)+(+d[3]);
Note: this code is not checking if its a valid ipv4 or not
Now when you have 2 numbers corresponding to 2 ips, you can compare it to check if its a range, also you can find how many ips in the range etc
How do I get the number of zero decimals behind the comma (but not the total)? So to illustrate an example:
0.00001 > 4
0.000015 > 4
0.0000105 > 4
0.001 > 2
I am looking for methods that are efficient (meaning that they optimize the calculation time).
You can use logarithms to find the magnitude of the number:
var x = 0.00195;
var m = -Math.floor( Math.log(x) / Math.log(10) + 1);
document.write(m); // outputs 2
Later versions of JavaScript have Math.log10, so it would be:
var x = 0.00195;
var m = -Math.floor( Math.log10(x) + 1);
document.write(m); // outputs 2
How using the base-10 logarithm of the numbers works:
x
Math.log10(x)
Math.floor(Math.log10(x) + 1 )
0.1
-1
0
0.01
-2
-1
0.015
-1.8239…
-1
0.001
-3
-2
0.00001
-5
-4
0.000015
-4.8239…
-4
0.0000105
-4.9788…
-4
Use a regex to match the number of zeros after a decimal point and then count them.
var zeros = float.toString().match(/(\.0*)/)[0].length - 1;
DEMO
Use this one:
function numberOfZeros(n) {
var c = 0;
while (!~~n) {
c++;
n *= 10;
}
return c - 1;
}
document.write(numberOfZeros(0.00065));
This code does the following: it multiplies the number by ten as long as it can be truncated to something not equal 0. The truncation operator "~~" is very performant, because it works with byte representation of the number directly.
It doesn't use any string operations and does exactly what you want: counts the zeros.
//my answer
function t1()
{
var num = 0.0000005323;
numOfZeroes = 0;
while(num < 1)
{
numOfZeroes++;
num *= 10;
}
}
//others
//Andrew Morton's answer
//https://stackoverflow.com/a/31002148/1115360
function t2()
{
var num = 0.0000005323;
var m = -Math.floor( Math.log10(num) + 1);
}
//Amy's Answer
//https://stackoverflow.com/a/31002087/4801298
function t3()
{
var r = 0.0000005323;
var count=0;
var splited = r.toString().split(".")[1];
for(var i=0;i<splited.length;i++)
{
if(splited[i]==0)
{
count++;
}
else
{
break;
}
}
}
//Ted's Answer
//https://stackoverflow.com/a/31002052/4801298
function t4()
{
var number = 0.0000005323;
var numberAsString = number.toString();
var decimalsAsString = numberAsString.substr(numberAsString.lastIndexOf('.')+1);
var leadingZeros = decimalsAsString.substr(0, decimalsAsString.lastIndexOf('0')+1).length;
}
//Bartłomiej Zalewski's answer
//https://stackoverflow.com/a/31001998/4801298
function t5()
{
var n = 0.0000005323;
var c = 0;
while (!~~n) {
c++;
n *= 10;
}
return c - 1;
}
//Andy 's answer
//https://stackoverflow.com/a/31002135/4801298
function t6()
{
var float = 0.0000005323;
var zeros = float.toString().match(/(\.0*)/)[0].length - 1;
}
//Praveen's answer
//https://stackoverflow.com/a/31002011/4801298
function t7()
{
var a = 0.0000005323;
return (a.toString().replace("0.", "").split("0").length - 1);
}
//benchmark function
function bench(func)
{
var times = new Array();
for(var t = 0; t < 100; t++)
{
var start = performance.now();
for(var i = 0; i < 10000; i++)
{
func();
}
var end = performance.now();
var time = end - start;
times.push(time);
}
var total = 0.0;
for(var i=0, l=times.length; i<l; i++)
total += times[i];
var avg = total / times.length;
return avg;
}
document.write('t1: ' + bench(t1) + "ms<BR>");
document.write('t2: ' + bench(t2) + "ms<BR>");
document.write('t3: ' + bench(t3) + "ms<BR>");
document.write('t4: ' + bench(t4) + "ms<BR>");
document.write('t5: ' + bench(t5) + "ms<BR>");
document.write('t6: ' + bench(t6) + "ms<BR>");
document.write('t7: ' + bench(t7) + "ms<BR>");
Note:
This would only work with numbers less than 1 of course. Otherwise, just remove numbers left of the decimal point first, like
num -= num % 1;
need to compare this to another way.
a while later...
I would like a better way to bench these function though. I might have my calculation wrong. I'm adding other peoples answers into the test. I'm now attempting to use the performance API
a bit later than before
AHA! Got it working. Here are some comparisons for you.
You can use something like this:
function num (a) {
return (a.toString().replace("0.", "").split("0").length - 1)
}
Here is a working example (a bit lengthy for clarity):
var number = 0.0004342;
var numberAsString = number.toString();
var decimalsAsString = numberAsString.substr(numberAsString.lastIndexOf('.')+1);
var leadingZeros = decimalsAsString.substr(0, decimalsAsString.lastIndexOf('0')+1).length;
// leadingZeros == 3
Convert the number in to a string and split it with the dot (.). Using the for loop to count the zeros occurrences.
var r = 0.0000107;
var count=0;
var splited = r.toString().split(".")[1];
for(var i=0;i<splited.length;i++)
{
if(splited[i]==0)
{
count++;
}
else
{
break;
}
}
console.log(count);
Node.js 9.0.0
I was looking for a solution without converting or the O(n) approach. Here is what solution I made by O(1).
Part of finding decimal by log – caught from #AndrewMorton, but it might be laggy with the divider: log(10) – 2.302585092994046.
Example
const normalize = (value, zeroCount) => {
const total = 10 ** zeroCount
const zeros = Math.floor(-Math.log10(value / total))
return value * (10 ** zeros)
}
Usage
normalize(1510869600, 13) // 1510869600000
normalize(1510869600, 10) // 1510869600
The following function works perfect, but when the amount over 1 million, the function don't work exactly.
Example:
AMOUNTPAID = 35555
The output is: 35.555,00 - work fine
But when the amount paid is for example: 1223578 (over 1 Million),
is the output the following output value: 1.223.235,00 (but it must be: 1.223.578,00) - there is a deviation of 343
Any ideas?
I call the function via HTML as follows:
<td class="tr1 td2"><p class="p2 ft4"><script type="text/javascript">document.write(ConvertBetrag('{{NETAMOUNT}}'))</script> €</P></TD>
#
Here ist the Javascript:
function Convertamount( amount ){
var number = amount;
number = Math.round(number * Math.pow(12, 2)) / Math.pow(12, 2);
number = number.toFixed(2);
number = number.toString();
var negative = false;
if (number.indexOf("-") == 0)
{
negative = true ;
number = number.replace("-","");
}
var str = number.toString();
str = str.replace(".", ",");
// number before decimal point
var intbeforedecimaln = str.length - (str.length - str.indexOf(","));
// number of delimiters
var intKTrenner = Math.floor((intbeforedecimaln - 1) / 3);
// Leading digits before the first dot
var intZiffern = (intbeforedecimaln % 3 == 0) ? 3 : (intbeforedecimaln % 3);
// Provided digits before the first thousand separator with point
strNew = str.substring(0, intZiffern);
// Auxiliary string without the previously treated digits
strHelp = str.substr(intZiffern, (str.length - intZiffern));
// Through thousands of remaining ...
for(var i=0; i<intKTrenner; i++)
{
// attach 3 digits of the nearest thousand group point to String
strNew += "." + strHelp.substring(0, 3);
// Post new auxiliary string without the 3 digits being treated
strHelp = strHelp.substr(intZiffern, (strHelp.length - intZiffern));
}
// attach a decimal
var szdecimal = str.substring(intbeforedecimaln, str.length);
if (szdecimal.length < 3 )
{
strNew += str.substring(intbeforedecimaln, str.length) + '0';
}
else
{
strNew += str.substring(intbeforedecimaln, str.length);
}
var number = strNew;
if (negative)
{
number = "- " + number ;
}
return number;
}
JavaScript's Math functions have a toLocaleString method. Why don't you just use this?
var n = (1223578.00).toLocaleString();
-> "1,223,578.00"
The locale you wish to use can be passed in as a parameter, for instance:
var n = (1223578.00).toLocaleString('de-DE');
-> "1.223.578,00"
Using Javascript, I want to format a number to always display 3 digits, along with it's proper identifier (ex: Million, Thousand). If under 100,000, the number should only show the "thousands" digits
All numbers will be integers above zero, and the highest numbers will be in the trillions.
A few examples of what I'm looking for:
1 Thousand
13 Thousand
627 Thousand
2.85 Million
67.9 Million
153 Million
9.52 Billion
etc...
All of the solutions I tried ended up becoming spaghetti code, and I am hoping someone can find a clean, smart solution.
EDIT:
I ended up using part of RobG's solution, but worked out the specifics on my own. I added rounding as well
function getNumberName(num) {
var numNames = ['', 'Thousand', 'Million', 'Billion', 'Trillion'];
num = num.toString();
var len = num.length - 1;
return numNames[len / 3 | 0];
}
function test(num) {
var numStr = num.toString();
if (num < 1000) {
return numStr;
} else if (num < 1000000) {
return numStr.slice(0, -3) + "," + numStr.slice(-3);
}
numStr = Math.round(parseFloat(numStr.slice(0, 3) + "." + numStr[3])).toString() + Array(numStr.slice(3).length + 1).join("0");
var remainder = numStr.length % 3;
var before = numStr.slice(0, remainder);
var after = numStr.slice(remainder, 3);
var sep = "";
if (before.length) {
sep = ".";
}
return before + sep + after + " " + getNumberName(num);
}
var nums = [0, 1, 12, 123, 1234, 12345, 123456, 1237567, 12325678, 123856789, 123e7, 125e8, 123.6e9, 123e10];
nums.forEach(function(num) {
document.write(num + ": $" + test(num) + "<br/>");
});
For integers, you can try shortening the number to the required number of places, then adding a name, e.g.
// For integers
function getNumberName(num) {
var numNames = ['','Thousand','Million','Billion'];
var num = num.toString()
var len = num.length - 1;
var pow = numNames[len/3 | 0];
return pow;
}
// For integers
function abbreviateNumber(num, places) {
places = places || 0;
var len = num.toString().length - 1;
var pow = len/3 | 0
return (num < 1000? num : num/Math.pow(10, pow*3)).toFixed(places);
}
function getNumberAbbr(num, places) {
return abbreviateNumber(num, places) + ' ' + getNumberName(num);
}
var nums = [0,1,12,123,1234,12345,123456,1234567,12345678,123456789,123e7]
nums.forEach(function(num) {
console.log(num + ' : ' + getNumberAbbr(num,1));
});
The above is not complete. There should be a limit applied so that beyond, say 1 trillion, it stops shortening the number.
There might be a better way but this will work:
function getTextNums(number) {
if ((number/1000000) < 1) {
var n = number.toString();
var first3 = n.substring(0, 3);
console.log(first3 + "Thousand");
} else if((number/1000000000) < 1) {
var n = number.toString();
var first3 = n.substring(0, 3);
console.log(first3 + "Million");
} else if((number/1000000000000) < 1) {
var n = number.toString();
var first3 = n.substring(0, 3);
console.log(first3 + "Billion");
} else if((number/1000000000000000) < 1) {
var n = number.toString();
var first3 = n.substring(0, 3);
console.log(first3 + "Trillion");
} else {
}
}
getTextNums(4533544433000)
How can I count the number of times a particular string occurs in another string. For example, this is what I am trying to do in Javascript:
var temp = "This is a string.";
alert(temp.count("is")); //should output '2'
The g in the regular expression (short for global) says to search the whole string rather than just find the first occurrence. This matches is twice:
var temp = "This is a string.";
var count = (temp.match(/is/g) || []).length;
console.log(count);
And, if there are no matches, it returns 0:
var temp = "Hello World!";
var count = (temp.match(/is/g) || []).length;
console.log(count);
/** Function that count occurrences of a substring in a string;
* #param {String} string The string
* #param {String} subString The sub string to search for
* #param {Boolean} [allowOverlapping] Optional. (Default:false)
*
* #author Vitim.us https://gist.github.com/victornpb/7736865
* #see Unit Test https://jsfiddle.net/Victornpb/5axuh96u/
* #see https://stackoverflow.com/a/7924240/938822
*/
function occurrences(string, subString, allowOverlapping) {
string += "";
subString += "";
if (subString.length <= 0) return (string.length + 1);
var n = 0,
pos = 0,
step = allowOverlapping ? 1 : subString.length;
while (true) {
pos = string.indexOf(subString, pos);
if (pos >= 0) {
++n;
pos += step;
} else break;
}
return n;
}
Usage
occurrences("foofoofoo", "bar"); //0
occurrences("foofoofoo", "foo"); //3
occurrences("foofoofoo", "foofoo"); //1
allowOverlapping
occurrences("foofoofoo", "foofoo", true); //2
Matches:
foofoofoo
1 `----´
2 `----´
Unit Test
https://jsfiddle.net/Victornpb/5axuh96u/
Benchmark
I've made a benchmark test and my function is more then 10 times
faster then the regexp match function posted by gumbo. In my test
string is 25 chars length. with 2 occurences of the character 'o'. I
executed 1 000 000 times in Safari.
Safari 5.1
Benchmark> Total time execution: 5617 ms (regexp)
Benchmark> Total time execution: 881 ms (my function 6.4x faster)
Firefox 4
Benchmark> Total time execution: 8547 ms (Rexexp)
Benchmark> Total time execution: 634 ms (my function 13.5x faster)
Edit: changes I've made
cached substring length
added type-casting to string.
added optional 'allowOverlapping' parameter
fixed correct output for "" empty substring case.
Gist
https://gist.github.com/victornpb/7736865
function countInstances(string, word) {
return string.split(word).length - 1;
}
console.log(countInstances("This is a string", "is"))
You can try this:
var theString = "This is a string.";
console.log(theString.split("is").length - 1);
My solution:
var temp = "This is a string.";
function countOccurrences(str, value) {
var regExp = new RegExp(value, "gi");
return (str.match(regExp) || []).length;
}
console.log(countOccurrences(temp, 'is'));
You can use match to define such function:
String.prototype.count = function(search) {
var m = this.match(new RegExp(search.toString().replace(/(?=[.\\+*?[^\]$(){}\|])/g, "\\"), "g"));
return m ? m.length:0;
}
Just code-golfing Rebecca Chernoff's solution :-)
alert(("This is a string.".match(/is/g) || []).length);
The non-regex version:
var string = 'This is a string',
searchFor = 'is',
count = 0,
pos = string.indexOf(searchFor);
while (pos > -1) {
++count;
pos = string.indexOf(searchFor, ++pos);
}
console.log(count); // 2
String.prototype.Count = function (find) {
return this.split(find).length - 1;
}
console.log("This is a string.".Count("is"));
This will return 2.
Here is the fastest function!
Why is it faster?
Doesn't check char by char (with 1 exception)
Uses a while and increments 1 var (the char count var) vs. a for loop checking the length and incrementing 2 vars (usually var i and a var with the char count)
Uses WAY less vars
Doesn't use regex!
Uses an (hopefully) highly optimized function
All operations are as combined as they can be, avoiding slowdowns due to multiple operations
String.prototype.timesCharExist=function(c){var t=0,l=0,c=(c+'')[0];while(l=this.indexOf(c,l)+1)++t;return t};
Here is a slower and more readable version:
String.prototype.timesCharExist = function ( chr ) {
var total = 0, last_location = 0, single_char = ( chr + '' )[0];
while( last_location = this.indexOf( single_char, last_location ) + 1 )
{
total = total + 1;
}
return total;
};
This one is slower because of the counter, long var names and misuse of 1 var.
To use it, you simply do this:
'The char "a" only shows up twice'.timesCharExist('a');
Edit: (2013/12/16)
DON'T use with Opera 12.16 or older! it will take almost 2.5x more than the regex solution!
On chrome, this solution will take between 14ms and 20ms for 1,000,000 characters.
The regex solution takes 11-14ms for the same amount.
Using a function (outside String.prototype) will take about 10-13ms.
Here is the code used:
String.prototype.timesCharExist=function(c){var t=0,l=0,c=(c+'')[0];while(l=this.indexOf(c,l)+1)++t;return t};
var x=Array(100001).join('1234567890');
console.time('proto');x.timesCharExist('1');console.timeEnd('proto');
console.time('regex');x.match(/1/g).length;console.timeEnd('regex');
var timesCharExist=function(x,c){var t=0,l=0,c=(c+'')[0];while(l=x.indexOf(c,l)+1)++t;return t;};
console.time('func');timesCharExist(x,'1');console.timeEnd('func');
The result of all the solutions should be 100,000!
Note: if you want this function to count more than 1 char, change where is c=(c+'')[0] into c=c+''
var temp = "This is a string.";
console.log((temp.match(new RegExp("is", "g")) || []).length);
A simple way would be to split the string on the required word, the word for which we want to calculate the number of occurences, and subtract 1 from the number of parts:
function checkOccurences(string, word) {
return string.split(word).length - 1;
}
const text="Let us see. see above, see below, see forward, see backward, see left, see right until we will be right";
const count=countOccurences(text,"see "); // 2
I think the purpose for regex is much different from indexOf.
indexOf simply find the occurance of a certain string while in regex you can use wildcards like [A-Z] which means it will find any capital character in the word without stating the actual character.
Example:
var index = "This is a string".indexOf("is");
console.log(index);
var length = "This is a string".match(/[a-z]/g).length;
// where [a-z] is a regex wildcard expression thats why its slower
console.log(length);
Super duper old, but I needed to do something like this today and only thought to check SO afterwards. Works pretty fast for me.
String.prototype.count = function(substr,start,overlap) {
overlap = overlap || false;
start = start || 0;
var count = 0,
offset = overlap ? 1 : substr.length;
while((start = this.indexOf(substr, start) + offset) !== (offset - 1))
++count;
return count;
};
var myString = "This is a string.";
var foundAtPosition = 0;
var Count = 0;
while (foundAtPosition != -1)
{
foundAtPosition = myString.indexOf("is",foundAtPosition);
if (foundAtPosition != -1)
{
Count++;
foundAtPosition++;
}
}
document.write("There are " + Count + " occurrences of the word IS");
Refer :- count a substring appears in the string for step by step explanation.
Building upon #Vittim.us answer above. I like the control his method gives me, making it easy to extend, but I needed to add case insensitivity and limit matches to whole words with support for punctuation. (e.g. "bath" is in "take a bath." but not "bathing")
The punctuation regex came from: https://stackoverflow.com/a/25575009/497745 (How can I strip all punctuation from a string in JavaScript using regex?)
function keywordOccurrences(string, subString, allowOverlapping, caseInsensitive, wholeWord)
{
string += "";
subString += "";
if (subString.length <= 0) return (string.length + 1); //deal with empty strings
if(caseInsensitive)
{
string = string.toLowerCase();
subString = subString.toLowerCase();
}
var n = 0,
pos = 0,
step = allowOverlapping ? 1 : subString.length,
stringLength = string.length,
subStringLength = subString.length;
while (true)
{
pos = string.indexOf(subString, pos);
if (pos >= 0)
{
var matchPos = pos;
pos += step; //slide forward the position pointer no matter what
if(wholeWord) //only whole word matches are desired
{
if(matchPos > 0) //if the string is not at the very beginning we need to check if the previous character is whitespace
{
if(!/[\s\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&\(\)*+,\-.\/:;<=>?#\[\]^_`{|}~]/.test(string[matchPos - 1])) //ignore punctuation
{
continue; //then this is not a match
}
}
var matchEnd = matchPos + subStringLength;
if(matchEnd < stringLength - 1)
{
if (!/[\s\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&\(\)*+,\-.\/:;<=>?#\[\]^_`{|}~]/.test(string[matchEnd])) //ignore punctuation
{
continue; //then this is not a match
}
}
}
++n;
} else break;
}
return n;
}
Please feel free to modify and refactor this answer if you spot bugs or improvements.
For anyone that finds this thread in the future, note that the accepted answer will not always return the correct value if you generalize it, since it will choke on regex operators like $ and .. Here's a better version, that can handle any needle:
function occurrences (haystack, needle) {
var _needle = needle
.replace(/\[/g, '\\[')
.replace(/\]/g, '\\]')
return (
haystack.match(new RegExp('[' + _needle + ']', 'g')) || []
).length
}
Try it
<?php
$str = "33,33,56,89,56,56";
echo substr_count($str, '56');
?>
<script type="text/javascript">
var temp = "33,33,56,89,56,56";
var count = temp.match(/56/g);
alert(count.length);
</script>
Simple version without regex:
var temp = "This is a string.";
var count = (temp.split('is').length - 1);
alert(count);
No one will ever see this, but it's good to bring back recursion and arrow functions once in a while (pun gloriously intended)
String.prototype.occurrencesOf = function(s, i) {
return (n => (n === -1) ? 0 : 1 + this.occurrencesOf(s, n + 1))(this.indexOf(s, (i || 0)));
};
function substrCount( str, x ) {
let count = -1, pos = 0;
do {
pos = str.indexOf( x, pos ) + 1;
count++;
} while( pos > 0 );
return count;
}
ES2020 offers a new MatchAll which might be of use in this particular context.
Here we create a new RegExp, please ensure you pass 'g' into the function.
Convert the result using Array.from and count the length, which returns 2 as per the original requestor's desired output.
let strToCheck = RegExp('is', 'g')
let matchesReg = "This is a string.".matchAll(strToCheck)
console.log(Array.from(matchesReg).length) // 2
Now this is a very old thread i've come across but as many have pushed their answer's, here is mine in a hope to help someone with this simple code.
var search_value = "This is a dummy sentence!";
var letter = 'a'; /*Can take any letter, have put in a var if anyone wants to use this variable dynamically*/
letter = letter && "string" === typeof letter ? letter : "";
var count;
for (var i = count = 0; i < search_value.length; count += (search_value[i++] == letter));
console.log(count);
I'm not sure if it is the fastest solution but i preferred it for simplicity and for not using regex (i just don't like using them!)
You could try this
let count = s.length - s.replace(/is/g, "").length;
We can use the js split function, and it's length minus 1 will be the number of occurrences.
var temp = "This is a string.";
alert(temp.split('is').length-1);
Here is my solution. I hope it would help someone
const countOccurence = (string, char) => {
const chars = string.match(new RegExp(char, 'g')).length
return chars;
}
var countInstances = function(body, target) {
var globalcounter = 0;
var concatstring = '';
for(var i=0,j=target.length;i<body.length;i++){
concatstring = body.substring(i-1,j);
if(concatstring === target){
globalcounter += 1;
concatstring = '';
}
}
return globalcounter;
};
console.log( countInstances('abcabc', 'abc') ); // ==> 2
console.log( countInstances('ababa', 'aba') ); // ==> 2
console.log( countInstances('aaabbb', 'ab') ); // ==> 1
substr_count translated to Javascript from php
Locutus (Package that translates Php to JS)
substr_count (official page, code copied below)
function substr_count (haystack, needle, offset, length) {
// eslint-disable-line camelcase
// discuss at: https://locutus.io/php/substr_count/
// original by: Kevin van Zonneveld (https://kvz.io)
// bugfixed by: Onno Marsman (https://twitter.com/onnomarsman)
// improved by: Brett Zamir (https://brett-zamir.me)
// improved by: Thomas
// example 1: substr_count('Kevin van Zonneveld', 'e')
// returns 1: 3
// example 2: substr_count('Kevin van Zonneveld', 'K', 1)
// returns 2: 0
// example 3: substr_count('Kevin van Zonneveld', 'Z', 0, 10)
// returns 3: false
var cnt = 0
haystack += ''
needle += ''
if (isNaN(offset)) {
offset = 0
}
if (isNaN(length)) {
length = 0
}
if (needle.length === 0) {
return false
}
offset--
while ((offset = haystack.indexOf(needle, offset + 1)) !== -1) {
if (length > 0 && (offset + needle.length) > length) {
return false
}
cnt++
}
return cnt
}
Check out Locutus's Translation Of Php's substr_count function
The parameters:
ustring: the superset string
countChar: the substring
A function to count substring occurrence in JavaScript:
function subStringCount(ustring, countChar){
var correspCount = 0;
var corresp = false;
var amount = 0;
var prevChar = null;
for(var i=0; i!=ustring.length; i++){
if(ustring.charAt(i) == countChar.charAt(0) && corresp == false){
corresp = true;
correspCount += 1;
if(correspCount == countChar.length){
amount+=1;
corresp = false;
correspCount = 0;
}
prevChar = 1;
}
else if(ustring.charAt(i) == countChar.charAt(prevChar) && corresp == true){
correspCount += 1;
if(correspCount == countChar.length){
amount+=1;
corresp = false;
correspCount = 0;
prevChar = null;
}else{
prevChar += 1 ;
}
}else{
corresp = false;
correspCount = 0;
}
}
return amount;
}
console.log(subStringCount('Hello World, Hello World', 'll'));
var str = 'stackoverflow';
var arr = Array.from(str);
console.log(arr);
for (let a = 0; a <= arr.length; a++) {
var temp = arr[a];
var c = 0;
for (let b = 0; b <= arr.length; b++) {
if (temp === arr[b]) {
c++;
}
}
console.log(`the ${arr[a]} is counted for ${c}`)
}