Check if a string starts with a number in range - javascript

I have a string that can be of random length and I need to check if it satisfies the following conditions:
starts with 4 digits
the first 4 digits form a number in range 2221-2720 (credit card number)
Right now I have the following code:
var isCardNumber = function (myString)
{
var num = parseInt(myString.substr(0, 4));
if(num) {
return num >= 2221 && num <= 2720;
};
return false;
};
Can this be done simpler/shorter? Probably with a regexp?

var isCardNumber = function ( cardNumber ) {
var n = +cardNumber.substr( 0, 4 )
return n && n > 2220 && n < 2721
}

Here is a regex for your general culture. As other said, I would not recommend using it. You could do performance tests but I'd expect it to be slower than the integer comparison test.
^2(2[2-9]\d|[3-6]\d\d|7([0-1]\d|2[0-1]))
To construct this kind of regex you need to break your range into easily reprensentable strings ; 2221-2720 is :
2220 to 2299 (22[2-9]\d)
2300 to 2699 (2[3-6]\d\d)
2700 to 2719 (27[0-1]\d)
2720 to 2721 (272[0-1])
Then you can factorise it as I did or just use it as is, with each fragment separated by a |.

Related

Each digit differs from the next one by 1

Script has to work this way:
isJumping(9) === 'JUMPING'
This is a one digit number
isJumping(79) === 'NOT JUMPING'
Neighboring digits do not differ by 1
isJumping(23454) === 'JUMPING'
Neighboring digits differ by 1
I have:
function isJumping(number) {
let str = number.toString();
for (let i = 1; i < str.length; i++) {
if (Math.abs(str[i+1]) - Math.abs(str[i]) == 1){
return 'JUMPING';
}
}
return 'NOT JUMPING';
}
console.log(isJumping(345));
Help please, where is mistake?
Loop over the characters and early return with "NOT JUMPING" if the condition is violated & if the condition is never violated return "JUMPING".
function isJumping(num) {
const strNum = String(Math.abs(num));
for (let i = 0; i < strNum.length - 1; i++) {
if (Math.abs(strNum[i] - strNum[i + 1]) > 1) {
// replace `> 1` with `!== 1`, if diff 0 is not valid!
return "NOT JUMPING";
}
}
return "JUMPING";
}
console.log(isJumping(9));
console.log(isJumping(79));
console.log(isJumping(23454));
There are a couple of issues:
You're not handling single digits.
You're returning too early. You're returning the first time you see a difference of 1 between digits, but you don't know that subsequent differences will also be 1.
You're not checking the difference between the first and second digits, and you're going past the end of the string.
You're using Math.abs as a means of converting digits to numbers.
Instead (see comments):
function isJumping(number) {
let str = number.toString();
for (let i = 1; i < str.length; i++) {
// Convert to number, do the difference, then
// use Math.abs to make -1 into 1 if necessary
if (Math.abs(+str[i] - str[i-1]) !== 1) {
// Found a difference != 1, so we're not jumping
return "NOT JUMPING";
}
}
// Never found a difference != 1, so we're jumping
return "JUMPING";
}
console.log(isJumping(345)); // JUMPING
console.log(isJumping(9)); // JUMPING
console.log(isJumping(79)); // NOT JUMPING
console.log(isJumping(23454)); // JUMPING
In that, I use +str[i] to convert str[i] to number and implicitly convert str[i-1] to number via the - operator, but there are lots of ways to convert strings to numbers (I list them here), pick the one that makes sense for your use case.
You might also need to allow for negative numbers (isJumping(-23)).
A clumsy way would be if (Math.abs(Math.abs(str[i+1]) - Math.abs(str[i])) == 1). Right now you are using Math.abs() to convert digits to numbers. Also, indexing is off, you start from 1, which is good, but then you should compare [i] and [i-1]. And the usual mismatch: you can say "JUMPING", only at the end. So you should check for !==1, and return "NOT JUMPING" inside the loop, and "JUMPING" after. That would handle the 1-digit case too.
It's a more readable practice to use parseInt() for making a number from a digit, otherwise the implementation of the comment:
function isJumping(number) {
let str = number.toString();
for (let i = 1; i < str.length; i++) {
if (Math.abs(parseInt(str[i-1]) - parseInt(str[i])) !== 1){
return 'NOT JUMPING';
}
}
return 'JUMPING';
}
console.log(isJumping(345));
console.log(isJumping(3));
console.log(isJumping(79));
You just need to check your single digit case, and then see if all the digits vary by just 1
function isJumping(number) {
let str = number.toString();
if(str.length == 1)
return 'JUMPING'
const allByOne = str.substring(1).split('').every( (x,i) => {
var prev = str[i];
return Math.abs( +x - +prev) == 1
})
return allByOne ? 'JUMPING' : 'NOT JUMPING';
}
console.log(isJumping(9));
console.log(isJumping(79));
console.log(isJumping(23454));
A vaguely functional approach... The find gets position of the first character pair where the gap is more than one. The .filter deals with negatives (and other extraneous characters) by ignoring them.
// default b to a, so that last digit case, where b===undefined, gives true
const gapIsMoreThanOne = (a,b=a) => ( Math.abs(a-b)>1);
const isDigit = n => /[0-9]/.test(n);
const isJumping = n => n.toString()
.split("")
.filter(isDigit)
.find((x,i,arr)=>gapIsMoreThanOne(x,arr[i+1]))
=== undefined
? "JUMPING" : "NOT JUMPING"
;
console.log(isJumping(1)); // JUMPING
console.log(isJumping(12)); // JUMPING
console.log(isJumping(13)); // NOT JUMPING
console.log(isJumping(21)); // JUMPING
console.log(isJumping(21234565)); // JUPING
console.log(isJumping(-21234568)); // NOT JUMPING
console.log(isJumping("313ADVD")); // NOT JUMPING
PS: To me "JUMPING" implies that there is a gap greater than one, not that there isn't: but I've gone with how it is in the question.

Javascript - String of a Byte with all combinations possible

i have a sting with a byte in it ("00001011") and now id like to get a array with all possible combinations of the 1 (acitve) "bits" in it also as a "byte string"
so from
var bString = "00001011"; //outgoing string
to a array with all string in it with all possible combinations of this "byte string" like - "00000001", "00000011", "00000010" and so on
is that possible?
thank you in advance
function combinations( input ){
var number = parseInt( input, 2 );
var combinations = [];
var zeroes = (new Array(input.length)).join(0);
for(var i=1;i<=number;i++){
if((i&number) == i){ combinations.push( i ) }
}
return combinations.map( function(dec){
return (zeroes + dec.toString(2)).substr( -zeroes.length-1 );
});
}
http://jsfiddle.net/jkf7pfxn/3/
console.log( combinations("00001011") );
// ["00000001", "00000010", "00000011", "00001000", "00001001", "00001010", "00001011"]
The idea goes as follows: iterate all numbers from 1 to the input number. If current number AND input number return the current number then both have 1 bits in the same place.
On a smaller number, "0101" (which is 5) it works as follows:
1 & 5 == 1, (0001 & 0101) push 1 to the matches.
2 & 5 == 0, (0010 & 0101) no match.
3 & 5 == 1, (0011 & 0101) no match.
4 & 5 == 4, (0100 & 0101) push 4 to the matches.
5 & 5 == 5, (0101 & 0101) push 5 to the matches.
So the combinations for 0101 are 1 (0001), 2 (0010), 4 (0100) and 5 (0101).
Then there's this little trick to pad numbers with zeroes:
var zeroes = (new Array(input.length)).join(0); // gives a long enough string of zeroes
then
// convert to base 2, add the zeroas at the beginning,
// then return the last n characters using negative value for substring
return (zeroes + dec.toString(2)).substr( -1 * zeroes.length);
Since 11111111 is 255 so just loop all values and convert them to binary
$(document).ready(function() {
for (var i = 0; i < 256; i++) {
$('#core').append('<div>' + dec2bin(i) + '</div>');
}
function dec2bin(dec) {
return ('00000000' + (dec >>> 0).toString(2)).slice(-8);
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id='core'></div>
If you want to enumerate all combinations of binary numbers where 1 can only be in the place of your pattern, you can write a simple recursive function:
var input = "00010111";
var current = [];
function combinations()
{
if (input.length === current.length)
{
var output = current.join('');
if (parseInt(output, 2) !== 0) // exclude all-zeroes case
document.body.innerHTML += output + "<br/>";
return;
}
current.push('0');
combinations();
current.pop();
if (input[current.length - 1] === '1')
{
current.push('1');
combinations();
current.pop();
}
}
combinations();
This algorithm works well for input of any length.
Although it is a recursion, it has a linear time complexity.

Match sequential digits

I am trying to make a function that can match sequential digits in a string that can also contains letters, such:
ae12 / aeg12345km / mea65 / ab2d43a21 / poe09ac etc.
The string should have sequential digits, which means any digit that are beside and in a sequence (12 is sequential, 1a2 is not sequential, 09 is sequential, a0b0 is not sequential, 00 is not sequential, 11 is not sequential, 112 is sequential)
I went on a couple of topics and it doesn't seem to be possible using regex.
I created this function but I'm not totally satisfied with it, I'd like to improve it:
containsSequentialDigits: function (str) {
var array = str.split('');
var previousC = null;
return array.some(function (c) {
if (isNaN(c)) {
previousC = null;
return false;
}
if (c === previousC+1 || c === previousC-1 ||
c === 0 && previousC === 9 || c === 9 && previousC === 0) {
return true;
}
previousC = c;
return false;
});
}
Do you have any suggestion to simplify it?
Thanks
I think that this regular expresion should work
/(0[19]|1[20]|2[31]|3[42]|4[53]|5[64]|6[75]|7[86]|8[97]|9[08])/
I'm also pretty sure a regex will do. Try this one:
function containsSequentialDigits(str) {
return /01|12|23|34|45|56|67|78|89|90|09|98|87|76|65|54|43|32|21|10/.test(str);
}
var s = [
's', // false, no digits
'1x2', // false, no consecutive digits
'2x1', // false, dito
'13', // false, not "sequential"
'12', // true, increasing
'21', // true, decreasing
];
for( var i = 0; i < s.length; i++ ) {
console.log( s[i], containsSequentialDigits(s[i]) );
}
Outputs:
"s" false
"1x2" false
"2x1" false
"13" false
"12" true
"21" true
The easiest way to do this is with a simple string of consecutive digits and the .indexOf() method. Assuming that you are looking for ONLY whether or not there are consecutive digits in the string and not what they are, the longest group of consecutive digits, or anything like that (that would take more coding :) ), then the following function would work:
function hasConsecutiveDigits(sValue) {
var sConsecutiveDigits = "012345678909876543210";
var regDigitPattern = /\d{2,}/g;
var aDigitGroups = sValue.match(regDigitPattern);
if (aDigitGroups !== null) {
for (j = 0; j < aDigitGroups.length; j++) {
for (x = 0; x < (aDigitGroups[j].length - 1); x++) {
var sCurrDigits = aDigitGroups[j].substring(x, x + 2);
if (sConsecutiveDigits.indexOf(sCurrDigits) !== -1) {
return true;
}
}
}
}
return false;
}
The sConsecutiveDigits string contains all of the possible consecutive digit patterns, so you can simply capture any group of one or more digits (using the regDigitPattern regex value) and then see if any two-digit subgroup of those groups exists as a substring of the sConsecutiveDigits string.
Additionally, since you are only looking for "yes, it has consecutive digits" or "no, it does not have consecutive digits", you can exit from the check as soon as you have found a match, cutting down on the processing a little.
I tested the function using the following code:
var aTestData = ["ae12", "aeg12345km", "mea65", "ab2d43a21", "poe09ac", "adsas", "asd13sad", "asda1357sd", "sd4dfg3dfg5df"];
for (i = 0; i < aTestData.length; i++) {
var result = hasConsecutiveDigits(aTestData[i]);
console.log("'" + aTestData[i] + "' " + ((result) ? "contains" : "does not contain") + " consecutive digits.")
}
. . . and recieved the following results:
'ae12' contains consecutive digits.
'aeg12345km' contains consecutive digits.
'mea65' contains consecutive digits.
'ab2d43a21' contains consecutive digits.
'poe09ac' contains consecutive digits.
'adsas' does not contain consecutive digits.
'asd13sad' does not contain consecutive digits.
'asda1357sd' does not contain consecutive digits.
'sd4dfg3dfg5df' does not contain consecutive digits.
UPDATE
I ran some speed tests on my solution and Daniel Böhmer's here: http://jsperf.com/duplicate-digit-check
Long story, short, they perform pretty similarly across the three prosers that I tested (IE 9, FF 31, and Chrome 40), with a very slight edge to the indexOf approach, most of the time.
The fact that all of my code runs as fas as a single regex check gives you an idea of how heavy regex can be. It's a great tool, but it should be used "gently". :)

Function that returns arbitrary decimal place on javascript

I want to make some function on javascript,
that receives some number and position number n and returns its nth decimal place.
That is,
nthdigit(3.5852,2) = 8
nthdigit(3.5852,3) = 5
nthdigit(3.5852,5) = 0
nthdigit(9.772,1) = 7
How can I do this correctly? Thanks.
Pure math solution:
function decimaldigit(num, n) {
return Math.floor(num * Math.pow(10, n)) % 10;
}
Convert the number to a String, split it on the decimal ., take the character you want and convert it back to a number.
function nthdigit(number, i) {
var afterDecimal = number.toString().split(".")[1];
return parseInt(afterDecimal.charAt(i-1));
}
I've chosen charAt(i-1) because character are counted starting 0 and it feels more natural in this case when you want the first number to put in 1.
This should be very easy to solve:
var nthdigit function(decimal, n)
{
var dec = '' + decimal; //convert to string
var decimalString = dec.split('.')[1]; //covert to array, take element with index [1]
var decimalPlaces = decimalSting.split(''); //covert to array
return parseInt(decimalPlaces( n-1 )); //1. decimalPlace has index 0
}
Another pure math solution, with better precision for high numbers and correct handling of negative numbers:
function nthdigit(num, n) {
return n ? nthdigit((num % 1) * 10, n-1) : Math.trunc(num);
}
using Math.trunc:
if (typeof Math.trunc != "function")
Math.trunc = function trunc(value) {
return value === 0 ? value : !isFinite(value) ? value : value | 0;
}

get the number of n digit in a 2+ digit number

For example, getting "5" in "256". The closest I've gotten is Math.floor(256/10)), but that'll still return the numbers in front. Is there any simple way to get what I want or would I have to make a big function for it? Also, for clarity: "n digit" would be defined. Example, getDigit(2,256) would return 5 (second digit)
Math.floor((256 / 10) % 10)
or more generally:
Math.floor(N / (Math.pow(10, n)) % 10)
where N is the number to be extracted, and n is the position of the digit. Note that this counts from 0 starting from the right (i.e., the least significant digit = 0), and doesn't account for invalid values of n.
how about
(12345 + "")[3]
or
(12345 + "").charAt(3)
to count from the other end
[length of string - digit you want] so if you want the 2 it's:
5 - 4 = 1
(12345 + "")[1] = "2"
function getNumber (var num, var pos){
var sNum = num + "";
if(pos > sNum.length || pos <= 0){return "";}
return sNum[sNum.length - pos];
}
First, you need to cast the number to a string, then you can access the character as normal:
var num = 256;
var char = num.toString()[1]; // get the 2nd (0-based index) character from the stringified version of num
Edit: Note also that, if you want to access it without setting the number as a variable first, you need a double dot .. to access the function:
var char = 256..toString()[1];
The first dot tells the interpreter "this is a number"; the second accesses the function.
Convert to string and substring(2,2)?
This should do it:
function getDigit ( position, number ) {
number = number + ""; // convert number to string
return number.substr ( position + 1, 1 ); // I'm adding 1 to position, since 0 is the position of the first character and so on
}
Try this, last line is key:
var number = 12345;
var n = 2;
var nDigit = parseInt((number + '').substr(1,1));
If you want to try to do everything mathematically:
var number = 256;
var digitNum = 2;
var digit = ((int)(number/(Math.pow(10,digitNum-1))%10;
This code counts the digit from the right starting with 1, not 0. If you wish to change it to start at 0, delete the -1 portion in the call.
If you wish to count from the left, it gets more complicated and similar to other solutions:
var number = 256;
var digitNum = 2;
var digit = ((int)(number/(Math.pow(10,number.tostring().length-digitNum))%10;
edit:
Also, this assumes you want base 10 for your number system, but both of those will work with other bases. All you need to do is change instances of 10 in the final line of code to the number representing the base for the number system you'd like to use. (ie. hexadecimal =16, binary = 2)
// You do not say if you allow decimal fractions or negative numbers-
// the strings of those need adjusting.
Number.prototype.nthDigit= function(n){
var s= String(this).replace(/\D+/g,'');
if(s.length<=n) return null;
return Number(s.charAt(n))
}
use variable "count" to control loop
var count = 1; //starting 1
for(i=0; i<100; i++){
console.log(count);
if(i%10 == 0) count++;
}
output will fill
1
2
3
4
5
6
7
8
9

Categories

Resources