user4563161
user4563161

Reputation:

REGEX - Input must have x unique digits

I was wondering if anyone knows a way for regex to detect that there has been a minimum of x digits used.

For example if I put in a number 6 digit number of 111222 but my regex says there must be at least 3 unique numbers this would cause a valid fail.

but if I had 123456 that would pass because there is more than three unique digits used.

Something like (obviously it wont be like bellow.)

/^[0-9]{6}*3$/

non regex way

var telcstart = $('#num').val(),
  telc1 = (telcstart.match(/1/g) || []).length,
  telc2 = (telcstart.match(/2/g) || []).length,
  telc3 = (telcstart.match(/3/g) || []).length,
  telc4 = (telcstart.match(/4/g) || []).length,
  telc5 = (telcstart.match(/5/g) || []).length,
  telc6 = (telcstart.match(/6/g) || []).length,
  telc7 = (telcstart.match(/7/g) || []).length,
  telc8 = (telcstart.match(/8/g) || []).length,
  telc9 = (telcstart.match(/9/g) || []).length,
  telc0 = (telcstart.match(/0/g) || []).length,
  totaltelc = "a:" + telc1 + " b:" + telc2 + " c:" + telc3 + " d:" + telc4 + "e:" + telc5 + " f:" + telc6 + " g:" + telc7 + " h:" + telc8 + " i:" + telc9 + " j:" + telc0,
  finaltelc = (totaltelc.match(/0/g) || []).length;

if (finaltelc <= 8) {
  alert('passed');
} else {
  alert('failed');
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<input type="number" id="num" value="123451212111">

Upvotes: 2

Views: 829

Answers (4)

MypKOT-1992
MypKOT-1992

Reputation: 191

function uniqueDigit(str)
{
    var a = 0;
    for (var i=0; i<10; i++)
    {
        (new RegExp( i, 'g')).test(str) && a++;
    }
    return a
}
console.log(uniqueDigit('10122211100')) // in str
console.log(uniqueDigit(222111333888))  // in int
var a = 123456;
console.log(/^\d{6}$/.test(a) && uniqueDigit(a) > 2) // example

Upvotes: 0

kennytm
kennytm

Reputation: 523224

^(?=.*(.)(?!$|.*\1))(?=.*(?!\1)(.)(?!$|.*\2))[0-9]+$

function check(value) {
  var res = document.getElementById('result');
  if (/^(?=.*(.)(?!$|.*\1))(?=.*(?!\1)(.)(?!$|.*\2))[0-9]+$/.test(value)) {
    res.innerText = '✓ OK';
  } else {
    res.innerText = '✗ No match';
  }
}
<p>Enter a number with ≥3 different digits</p>
<p><input type=text onkeyup='check(this.value)'> <span id=result></span></p>

Let's split it up:

^
(?=
    .*(.)       # Pick any character in the string as group 1
    (?!$|.*\1)  # Ensure this is not the last character, but is the last unique character
)
(?=
    .*(?!\1)(.) # Pick another character in the string as group 2
    (?!$|.*\2)  # Same condition as above 
)
[0-9]+
$

The first condition ensures there is a string like ??1??a. The second condition ensures a string like ???2?b, where 1a and 2b and 12. From this we can conclude there are at least 3 different characters.


This can be easily generalized to e.g. at least 8 different characters needed:

^
(?=.*(.)(?!$|.*\1))
(?=.*(?!\1)(.)(?!$|.*\2))
(?=.*(?!\1|\2)(.)(?!$|.*\3))
(?=.*(?!\1|\2|\3)(.)(?!$|.*\4))
(?=.*(?!\1|\2|\3|\4)(.)(?!$|.*\5))
(?=.*(?!\1|\2|\3|\4|\5)(.)(?!$|.*\6))
(?=.*(?!\1|\2|\3|\4|\5|\6)(.)(?!$|.*\7))
[0-9]+
$

Because JavaScript only support up to \9, you can't use this method to check more than 10 different characters. At this point you should really question whether regex is a right tool for this job though 😉.

Upvotes: 1

Pedro Castilho
Pedro Castilho

Reputation: 10512

You actually can do this with a regex, but it'll be very ugly and near-incomprehensible.

Looking at just one case, we can write a regex for a string that contains 0, 1, and at least one number from 2 to 9:

/^0(\d)*1(\d)*[2-9](\d)*$/

For each possible pair of numbers, we would have to write a regex like this ad combine all of them using | so that we catch all cases.

There are 10*9 = 90 pairs of distinct digits, and for each group there are 2 permutations, totalling 180 groups.

So we would have to do:

/(^0(\d)*1(\d)*[2-9](\d)*$/)|(^0(\d)*2(\d)*(1|[3-9])(\d)*$/)| ... /

Continuing for all 180 groups. That would be a gigantic regex, and would probably take a very long while to compile.

You should do this validation with code instead of running a regex.

EDIT: Apparently, JavaScript regexes have some extended features which make this doable, namely reusing the value captured by a given group. refer to @kennytm's answerr.

Upvotes: 1

anubhava
anubhava

Reputation: 785058

Based on negative lookaheads you can ensure a different digit matches three times:

(\d)\d*?((?!\1)\d)\d*?(?!\1|\2)\d+$

RegEx Demo

  • (?!\1) negative lookahead to ensure next match is not same as captured group #1
  • (?!\1|\2) negative lookahead to ensure next match is not same as captured group #1 and group #2

Upvotes: 0

Related Questions