How to check if a digit appears more than once in a number (anywhere within it)?
Example input numbers:
1, 10, 11, 1010, 1981
Output should tell which of them has any repeated digits:
false, false, true, true, true
Publihsed all the good answers given in a jsperf page
I think the fastest way would be a RegExp test. You can use it to get a quick true or false on whether there is a repeat, and it's compact enough to use in conditional operators. Here's an example that'd work with numbers and strings of numbers.
function hasRepeatingdigits(N) {
return (/([0-9]).*?\1/).test(N)
}
console.log(
[1, 10, 11, 1010, 1981, 12345678901, 123456789].map(hasRepeatingdigits)
)
(Edit -Isaac B)
Here's a breakdown of how the RegExp works:
The [0-9] creates a list of single characters between 0 and 9 to be
matched.
Adding the parentheses ([0-9]) defines this list as the
first capture group. These parens would not be needed if you were only searching for a char and didn't need the RegExp to perform a subsequent action. (i.e. /[0-9]/ is all you need to find the first index of a char 0 through 9 in a string, or true in a RegExp test)
The . matches any single char - except for line terminators. Adding the lazy quantifier *? matches between 0 and infinity times, as few time as possible.
The \1 matches the same text as most recently matched by the first capture group
In summary: /([0-9]).*?\1/ is a regular expression that iterates through a string looking for each char 0 through 9 and returning a match the first time a match is found to the char currently in the first capture group.
In the string '123432', this RexExp would return a full match: '2343' on capture group 1: '2'.
RegExp.prototype.test() searches a string using the provided RegExp and returns true if the RegExp return a match, else it returns false. This could easily be modified to find a duplicate letter char as well using /([A-Za-z]).*?\1/).test(N).
Beyond the very useful MDN section on RegExp, I highly recommend people working to get more comfortable with them to check out this RegularExpressions101 tool.
function checkForRepeatingDigits(N){
var arr = (''+N).split(''),
result = arr.filter((elem, i) => arr.indexOf(elem) == i);
return result.length != (''+N).length;
}
// Or
function checkForRepeatingDigits(N){
return [...new Set((''+N).split(''))].length != (''+N).length;
}
console.log([1, 10, 11, 1010, 1981].map(checkForRepeatingDigits))
You could use a check with Array#indexOf and Array#lastIndexOf.
function check(a, _, aa) {
return aa.indexOf(a) !== aa.lastIndexOf(a);
}
console.log([1, 10, 11, 1010, 1981].map(a => a.toString().split('').some(check)));
Short solution using Array.prototype.map() and String.prototype.match() function:
function checkForRepeatingDigits(N) {
return N.map(function (v) {
return [v, Boolean(String(v).match(/(\d)\d*?\1/g))];
});
}
console.log(checkForRepeatingDigits([1, 10, 11, 1010, 1981]));
function repeated(n) {
var digits = [];
var digit;
while (n) {
digit = n % 10;
if (digits[digit]) return true;
digits[digit] = true;
n = Math.floor(n / 10);
}
return false;
}
[1, 10, 11, 1010, 1981].forEach(n => console.log(n, repeated(n)));
This works by first converting the number to a string with N = N + '' and then checking the result of split(), which is a String function that crushes a string to smaller parts based on a delimiter.
For example, if I split "aba" by "b", I'll get an array containing ["a", "a"]. As you can see, if there's one occurrence of "b", the length of the returned array is 2. If there's more, it will be over 2. This is what I use in my solution.
As a bonus, it works with other types of data, even null and undefined. ;)
function check(N) {
for (var N = N + '', i = (N).length; i--;)
if (N.split(N[i]).length > 2)
return true;
return false;
}
[1, 10, 11, 1010, 1981, "abcd23", "aab", "", null, undefined].forEach(num => {
console.log(num, check(num));
});
const isRepeated = (num) => new Set('' + num).size != ~~Math.log10(num) + 1;
[1, 10, 11, 1010, 1981].forEach(n => console.log(n, isRepeated(n)));
JS offers a Set object which is a data type to hold unique elements, ie. it will remove any duplicates from the input, thus, new Set(string) removes all duplicate characters from the string, thus, we do new Set('' + num) to pass num as a string, now that the set contains only unique characters, set.size will return number of unique characters in the string.
A number will have no repeated characters if the number of digits is equal to number of unique characters we found earlier, there are many ways to find number of digits in number, we could also do num.toString().length instead of ~~Math.log10(num) + 1, the logarithm of a number to base 10 gives us a decimal value, we convert it to integer, this integer will be 1 less than the number of digits, so, we add 1 to get number of digits.
Thus, it returns true when the lengths are not equal, implying that there is repetition, and false otherwise.
Related
I am working on a Chat bot for discord that has an addition calculator.... I am currently trying to find the .indexOf the first time a number appears in the string... For ex: !add 1 + 1 would be the command to add 1 and 1... I have an array that I use that contains all single numbers ex:
const singleNumbers = [
0,
1,
2,
3,
4,
5,
6,
7,
8,
9,
];
when I get the string back I am using
for (const num of singleNumbers){
const num1 = msg.content.indexOf(num,);
const add = '+';
const locationOfAdd = msg.content.indexOf(add,);
const num2 = msg.content.indexOf(num,locationOfAdd);
const add1 = msg.content.slice(num1,) * 1;
const add2 = msg.content.slice(num2,) * 1;
msg.reply(add1 + add2);
}
When I run this... It for some reason will only use the first number of the Array so the numbers I use in !add 1 + 1 have to start with 0... so !add 01 + 01 which in math is fine... but for simplicity how do I make it be able to start with any number in the array rather than the first... If you don't know discord.js,
msg.content
Is the string returned so if I type in chat...
Hey Guys what's goin on?
it would return as a String ("Hey Guys what's goin on?")...
To sum this all up... I am wondering how to make my const num that I declared in my for of loop check for all the numbers in its array rather than just the first in my case 0.
If you just want to find the index for the first digit str.search(/[0-9]/) or str.match/[0-9]/).index.
Using regex to extract the numbers, and reduce to add them:
match on: string starts with !add, at least one space, at least one digit as a capture group, optional space and a + sign, another series of digits as a capture group.
You get an array with [full match, digit group 1, digit group 2]. I slice off the full match, and then use reduce to (+x converts the string to a number; you could also use Number(x)) to add each number and collect it in sum.
const sum = msg.content.match(/^!add\s+(\d+)\s*\+\s*(\d+)/).slice(1).reduce((sum,x)=>+x+sum,0)
Note: \d is the same as [0-9]
JavaScript.info RegExp tutorial
I was solving the Coderbyte Challenge - Questions Marks
When I run my code in the browser it all works fine, however, once I run it on the coderbyte website it throws an error.
The Challenge is:
Have the function QuestionsMarks(str) take the str string parameter,
which will contain single digit numbers, letters, and question marks,
and check if there are exactly 3 question marks between every pair of
two numbers that add up to 10. If so, then your program should return
the string true, otherwise it should return the string false. If there
aren't any two numbers that add up to 10 in the string, then your
program should return false as well.
For example: if str is "arrb6???4xxbl5???eee5" then your program
should return true because there are exactly 3 question marks between
6 and 4, and 3 question marks between 5 and 5 at the end of the
string.
Use the Parameter Testing feature in the box below to test your code
with different arguments.
Test Cases Are:
"arrb6???4xxbl5???eee5" true
"aa6?9" false
"acc?7??sss?3rr1??????5" true
My solution to this was to use RegExp to solve the challenge. the code below works well when I run it in the Browser, however, Coderbyte console throws an error every time:
/tmp/009904362/main.js:11 clean = clean.match(/d(???)d/gi); ^SyntaxError: Invalid regular expression: /d(???)d/
Here is my code -
function QuestionsMarks(str) {
//create a "clean" array containing only the numbers and question marks from str
var result;
let clean = str.match(/[0-9?]/g);
// join() the array back in to the string
clean = clean.join("");
// use match() to return an array of pairs that match the pattern d???d
clean = clean.match(/d(\?\?\?)d/gi);
//create a function sumCheck() that converts first and last char of every array string to Number and checks if the sum of digits is 10
//using forEach() run the sumcheck() on all strings in the array
clean.forEach(sumCheck);
function sumCheck(string){
if((Number(string.charAt(0)) + Number(string.charAt(string.length - 1))) == 10){
result = true;
}else{
result = false;
}
}
return result;
}
QuestionsMarks("acc?7??sss?3rr1??????5");
The problem seems to come from Coderbyte that isn't able to parse correctly escaped characters in regex patterns (literals or with the RegExp constructor). So the simplest solution is to replace escaped sequences: \d => [0-9], and \? => [?] (as suggested by #Saud in comments).
About your approach:
... check if there are exactly 3 question marks between every pair of two numbers that add up to 10 ...
What does your corrected pattern /[0-9][?]{3}[0-9]/g?It looks for digits separated by three question marks (and then you check if the sum of two digits is 10). Even if this pattern would be able to find all pair of digits separated by three question marks in the string (that isn't the case(*)), It doesn't check if there are digits that add up to 10 and that aren't separated by exactly 3 question marks!
So, the goal is to find if the string contains a pair of digits that add up to 10 without the 3 question marks. If this pair exists the function returns false.
(*): Why /[0-9][?]{3}[0-9]/g isn't able to find all pair of digits separated by 3 question marks?
Example with: 1???2???3???4
Because you can't match the same character twice. The pattern will find: 1???2 and 3???4 but not 2???3 since the 2 is already consumed by the first match.
A possible way to do it:
function QuestionsMarks(str) {
var state = { d1: 0, d2: 0, marks: 0,
init: function() { this.d1 = this.d2; this.marks = 0; },
check: function() { return this.d1 + this.d2 > 9 && this.marks != 3; }
};
var re = /[0-9?]/g;
var m;
while ( (m = re.exec(str)) !== null ) {
if ( m[0] == '?' ) {
state.marks++;
} else {
state.d2 = parseInt(m[0]);
if ( state.check() ) return false;
state.init();
}
}
return true;
}
I am trying to make a regex to matches all the combinations of a given string. For example of the string is "1234", answers would include:
"1"
"123"
"4321"
"4312"
Nonexamples would include:
"11"
"11234"
"44132"
If it matters, the programming language I am using is javascript.
Thank you for any help.
You may use this lookahead based assertions in your regex:
^(?!(?:[^1]*1){2})(?!(?:[^2]*2){2})(?!(?:[^3]*3){2})(?!(?:[^4]*4){2})[1234]+$
RegEx Demo
Here we have 4 lookahead assertions:
(?!(?:[^1]*1){2}): Assert that we don't have more than one instance of 1
(?!(?:[^2]*2){2}): Assert that we don't have more than one instance of 2
(?!(?:[^3]*3){2}): Assert that we don't have more than one instance of 3
(?!(?:[^4]*4){2}): Assert that we don't have more than one instance of 4
We use [1234]+ to match any string with these 4 characters.
A combination of group captures using character classes and negative look-ahead assertions using back-references would do the trick.
Let's begin with simply matching any combination of 1, 2, 3, and 4 using a character class,[1-4], and allowing any length from 1 to 4 characters. {1,4}.
const regex = /^[1-4]{1,4}$/;
// Create set of inputs from 0 to 4322
const inputs = Array.from(new Array(4323), (v, i) => i.toString());
// Output only values that match criteria
console.log(inputs.filter((input) => regex.test(input)));
When that code is run, it's easy to see that although only numbers consisting of some combination of 1, 2, 3, and 4 are matched, it also is matching numbers with repeating combinations (e.g. 11, 22, 33, 112, etc). Obviously, this was not what was desired.
To prevent repeating characters requires a reference to previously matched characters and then a negation of them from any following matched characters. Negative look-aheads, (?!...) using a back-reference, \1-9, can accomplish this.
Building on the previous example with a subset of the inputs (limiting to a max length of two characters for the moment) would now incorporate a group match surrounding the first character, ([1-4]), followed by a negative look-ahead with a back-reference to the first capture, (?!\1), and finally a second optional character class.
const regex = /^([1-4])(?!\1)[1-4]?$/;
// Create set of inputs from 0 to 44
const inputs = Array.from(new Array(45), (v, i) => i.toString());
// Output only values that match criteria
console.log(inputs.filter((input) => regex.test(input)));
This matches the desired characters with no repetition!
Expanding this pattern to include back-references for each of the previously matched characters up to the desired max length of 4 yields the following expression.
const regex = /^([1-4])((?!\1)[1-4])?((?!\1|\2)[1-4])?((?!\1|\2|\3)[1-4])?$/;
// Create set of inputs from 0 to 4322
const inputs = Array.from(new Array(4323), (v, i) => i.toString());
// Output only values that match criteria
console.log(inputs.filter((input) => regex.test(input)));
Hope this helps!
You don't need to use regex for this. The snippet below does the following:
Loop over possible combinations (a => s) (1, 123, 4321, etc.)
Copy the current combination so as not to overwrite it (s2 = s)
Loop over the characters of test string (x => ch) (1234 => 1, 2, 3, 4)
Replace common characters in the combination string shared with the test string (s2.replace)
For example in the combination 1, the 1 will be replaced when the loop gets to the character 1 in 1234 resulting in an empty string
If the combination string's length reaches 0 (s2.length == 0) write the result to the console and break out of the loop (no point in continuing to attempt to replace on an empty string)
const x = "1234"
const a = ["1","123","4321","4312","11","11234","44132"]
a.forEach(function(s) {
var s2 = s
for(var ch of x) {
s2 = s2.replace(ch, '')
if(s2.length == 0) {
console.log(s);
break;
}
}
})
Results:
1
123
4321
4312
I want to check using "pattern" attribute that the user can't enter two similar digits like: 1232, 1222, 1229 etc.
After googling, I found something like this: pattern="^1(?:([2-9])(?!\1))+$", but it doesn't work for 1232 (for example) and it doesn't consider how many digits you enter.
You can use the following:
^(?!.*(\d).*\1)1\d{3}$
It works by requiring a 1, and then 3 more digits. It uses a negative lookahead to verify that a digit is not repeated anywhere in the 4 numbers.
Run the example below for test cases:
let regex = /^(?!.*(\d).*\1)1\d{3}$/;
function test(numberAsString) {
console.log(numberAsString, regex.test(numberAsString));
}
test('1232'); // false, number repeated
test('1222'); // false, number repeated
test('1229'); // false, number repeated
test('1234'); // true
test('2345'); // false, 1 does not start
test('1789'); // true
test('12345'); // false, too many digits
test('123'); // false, too little digits
An explanation of the Regular Expression:
1\d{3}
is the part that says it needs a 1, and then 3 more digits
(?!.*(\d).*\1)
is a negative lookahead (note the (?!). It scans the entire input (.*), until it finds a digit (\d) that is captured (surrounded by ()), and scans the rest of the string (.*), looking for a copy of itself (\1) or in other words, what the first capture was. In simpler terms, here is an example for a 1 that cannot be followed by a 1 at any point: (?!.*1.*1). But since you are using a special character for any digit (\d), you can assert that any digit found is not repeated.
^
asserts the beginning of the string
$
asserts the end of the string. These beginning and ending assertions are needed so that strings like asd1234 do not pass validation.
Check this out
// Magical function.
var checkDigits = function(num, maxLength) {
let allDigits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
try {
if (num.length < 1 || num.length > maxLength) throw new Error("You need to enter exactly " + maxLength + " digits");
for (let i = 0; i < num.length; i++) {
if (allDigits[num[i]] === null) throw new Error("You repeated a digit in your sequence");
allDigits[num[i]] = null;
}
} catch (e) {
console.error(e);
return false
}
return allDigits;
};
// Getting data from dom.
var num = document.getElementById("num").value;
// Trying to see the data in the console.
if (num[0] == 1) console.log(checkDigits(num.slice(1)));
Well that's all I could say, I hope you understood
EDIT: Oops I missed the one part sorry.
Cheers,
Rj
Javascript regex to validate that it contains 6 characters and in which one character (1) should be a number.
var pwdregex =/^[A-Za-z1-9]{6}$/;
This will guarantee exactly one number (i.e. a non-zero decimal digit):
var pwdregex = /^(?=.{6}$)[A-Za-z]*[1-9][A-Za-z]*$/;
And this will guarantee one or more consecutive number:
var pwdregex = /^(?=.{6}$)[A-Za-z]*[1-9]+[A-Za-z]*$/;
And this will guarantee one or more not-necessarily-consecutive number:
var pwdregex = /^(?=.{6}$)[A-Za-z]*(?:[1-9][A-Za-z]*)+$/;
All of the above expressions require exactly six characters total. If the requirement is six or more characters, change the {6} to {6,} (or remove the $ from {6}$).
All possible combinations of 1 digit and alphanumeric chars with a length of 6.
if (subject.match(/^[a-z]{0,5}\d[a-z]{0,5}$/i) && subject.length == 6) {
// Successful match
} else {
// Match attempt failed
}
[Edit] Fixed obvious bug...
If you are ok with using a function instead of a regex you can do this:
var sixAlphaOneDigit = function(s) {
return !!((s.length==6) && s.replace(/\d/,'').match(/^[A-Za-z]{5}$/));
};
sixAlphaOneDigit('1ABCDE'); // => true
sixAlphaOneDigit('ABC1DE'); // => true
sixAlphaOneDigit('ABCDE1'); // => true
sixAlphaOneDigit('ABCDE'); // => false
sixAlphaOneDigit('ABCDEF'); // => false
sixAlphaOneDigit('ABCDEFG'); // => false
If you want to do it strictly in a regex then you could build a terribly long pattern which enumerates all possibilities of the position of the digit and the surrounding (or leading, or following) characters.