3

I am trying to figure it out how can I check if a string has three ascending letters and/or number in a string. For example, if a string has "manabcrt" then there is "abc" or "castle567", there is "567" in the string or "castlexyzand789" it has "xyz" and 789 ... so I want to check for that. I find this one fiddle but it is doing for the repeating letters.

This is the code from the fiddle:

var inputs = [
'helloworld',
'hellloworld',
'aaabc',
'abcddd',
'bbabba'];

var violators = [];
inputs.forEach(function(input) {
if (/(.)\1\1/.test(input)) {
    violators.push(input);
}});
alert("VIOLATORS:\n" + violators.join('\n'));
jeewan
  • 1,597
  • 5
  • 23
  • 40
  • 4
    you will probably over-complexify your problem by using a regex, the situation is different than a repetition. I suggest you give a try with loops instead.. – Kaddath Jan 31 '18 at 15:24
  • Only 3 letters? – Srdjan M. Jan 31 '18 at 15:26
  • 1
    yes only three letter and/or number. This is for the password validation while creating a new account. So the user can not have password like "castle123" or "javaxyz" or "p456ythonjkl" – jeewan Jan 31 '18 at 15:27
  • I agree with @Kaddath. Try it with looping, and post your code here if you need help with it. – freginold Jan 31 '18 at 15:28
  • I am able to do for the numbers here https://jsfiddle.net/qw6a1yk2/ but I need to do the same for the letters now. – jeewan Jan 31 '18 at 15:31
  • 1
    When you say that you want an ascending character sequence, do you mean that they must be strictly 1 position after the other, or do a sequence like `acd` is also valid? – Pedro Corso Jan 31 '18 at 15:38
  • How does 0 figure in? Is `0123` allowed? What about `890`? – freginold Jan 31 '18 at 15:42
  • yes "acd" is valid ... only restriction is it can not be three regularly like abc, def, fgh etc ... I am tying to convert it in key code with charCodeAt() method ... lets see if that works – jeewan Jan 31 '18 at 15:46
  • 0123 is not allowed and 890 is also not allowed. – jeewan Jan 31 '18 at 15:57
  • If `890` is not allowed, then `901`, `yza` and `zab` are also not allowed? – Pedro Corso Jan 31 '18 at 16:03
  • yes, any "circular" consecutive letters/numbers are also not valid. – jeewan Jan 31 '18 at 19:31
  • @jeewan please don't create password rules. See [Reference - Password Validation](https://stackoverflow.com/questions/48345922/reference-password-validation) for more info. Password rules actually make your passwords less secure. – ctwheels Feb 01 '18 at 14:17

6 Answers6

5

It's a dull exercise but you are probably best off spelling out all possible triplets ( 10 + 2*26 ) in your regex, testing for their presence:

(012|123|234|345|456|567|678|789|890|901|abc|bcd|cde|def|efg|fgh|ghi|hij|ijk|jkl|klm|lmn|mno|nop|opq|pqr|qrs|rst|stu|tuv|uvw|vwx|wxy|xyz|yza|zab|ABC|BCD|CDE|DEF|EFG|FGH|GHI|HIJ|IJK|JKL|KLM|LMN|MNO|NOP|OPQ|PQR|QRS|RST|STU|TUV|UVW|VWX|WXY|XYZ|YZA|ZAB)

Of course, this approach fails on non-latin characters.

See the live demo (Regex101).

To use it in your code, replace

if (/(.)\1\1/.test(input)) {
    violators.push(input);
}});

with

if (/(012|123|234|345|456|567|678|789|890|901|abc|bcd|cde|def|efg|fgh|ghi|hij|ijk|jkl|klm|lmn|mno|nop|opq|pqr|qrs|rst|stu|tuv|uvw|vwx|wxy|xyz|yza|zab|ABC|BCD|CDE|DEF|EFG|FGH|GHI|HIJ|IJK|JKL|KLM|LMN|MNO|NOP|OPQ|PQR|QRS|RST|STU|TUV|UVW|VWX|WXY|XYZ|YZA|ZAB)/.test(input)) {
    violators.push(input);
}});
collapsar
  • 17,010
  • 4
  • 35
  • 61
  • 3
    This question was tagged regex and this is the only regex answer. Even if it isn't a pretty and realistic solution, it is working. **so why the downvotes**? (PS. You could skip the uppercase tests and just add the `i` flag for case insensitive test.) – SamWhan Jan 31 '18 at 16:20
  • agree. I put `9 + 2*24` into google and guess what it's only 57! seems like it's quite easy to comprehend once written, while in the real world, Nina's shockingly clever answer (also upvoted) would require massive commenting so that other devs would (perhaps) grasp the algorithm. – Scott Weaver Jan 31 '18 at 16:25
  • @ClasG Thanks for the moral support :). Case-insensitive matching would flag triplets of mixed case (like 'aBc') which in the strict sense and given the pw validation context would not be considered 'ascending'. In general, of course, you are right. – collapsar Jan 31 '18 at 16:25
5

You could check the values by counting the ascending pairs.

var array = ['manabcrt', 'castle567', , 'castlexyzand789', 'helloworld', 'hellloworld', 'aaabc', 'abcddd', 'bbabba'],
    check = array.filter(s => {
        var v = 1;
        return [...s].some((c, i, a) => {
            v *= parseInt(c, 36) + 1 === parseInt(a[i + 1], 36);
            return ++v === 3;
        });
    });
    
console.log(check);

Some adjustment to the cases '90' and for not including '9a'

var array = ['zab', '901', '9ab', 'manabcrt', 'castle567', , 'castlexyzand789', 'helloworld', 'hellloworld', 'aaabc', 'abcddd', 'bbabba'],
    check = array.filter(s => {
        var v = 1;
        return [...s].some((c, i, a) => {
            var l = parseInt(c, 36),
                r = parseInt(a[i + 1], 36);

            v *= l + 1 === r && l !== 9 && r !== 10 || l === 9 && r === 0 || l === 35 && r === 10;
            return ++v === 3;
        });
    });
    
console.log(check);
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
2

With Array.filter() and String.charCodeAt() functions:

var inputs = ['manabcrt', 'castle345', 'helloworld', 'abcddd', 'password'],
    invalid_items = inputs.filter(function(w){
        var len = w.length;            // word length
        for (i=0; i<=len-3; i+=3) {    // iterating over 3-char sequences
            var char_code = w[i].charCodeAt(0);
            if (w[i+1].charCodeAt(0) - char_code == 1 &&
                w[i+2].charCodeAt(0) - char_code == 2) {
                return true;
            }
        }
        return false;
    });

console.log(invalid_items);

Performance test result: enter image description here

RomanPerekhrest
  • 88,541
  • 4
  • 65
  • 105
  • wow that is a great analysis ... something need to consider ... but my current case is a small block of code, maybe I will be creating a function just to check that consecutive letters/numbers ... but thanks for this, I will need to think which way to go ... both solutions are good to me so thank you so much you all guys. – jeewan Jan 31 '18 at 19:29
0

For any substring length

function containsNAscLetters(input, n){
    for(var j = 0; j<=input.length-n; j++){
        var buf = input.substring(j, j+n);
        if (buf.split('').sort().join('').toString()===buf) return buf;
    }
    return null;
}

containsNAscLetters("avfabc", 3)
vadzim dvorak
  • 939
  • 6
  • 24
0

Without too much complication, you could do it with a for loop, even allowing for sequences with length greater than 3:

function hasAscSequence(str, limit){
  var count = 0;
  for(var i = 1; i<str.length;i++){
    if(str.charCodeAt(i) - str.charCodeAt(i-1) == 1) count++;
    else count = 0;
    if(count == limit-1) return true
  }
  return false;
}

var inputs = [
'helloworld',
'hellloworld',
'aaabc',
'abcddd',
'bbabba'];

console.log(inputs.filter(x=>!hasAscSequence(x, 3)));
Pedro Corso
  • 557
  • 8
  • 22
0

In the case that you also don't want to match 3 descending chars in a row as well:

let inputs = [
    'helloworld',
    'hellloworld',
    'aaabc',
    'abcddd',
    'bbabba',
    'cbaheop'
  ],
  valid = [];

inputs.forEach((password) => {
  let passValid = true;
    for (i = 0; i < password.length - 2; i++) {
      let currentChar = password.charCodeAt(i),
        oneCharLater = password.charCodeAt(i + 1),
        twoCharLater = password.charCodeAt(i + 2);

      if ((currentChar + 1 === oneCharLater && currentChar + 2 === twoCharLater) || (currentChar - 1 === oneCharLater && currentChar - 2 === twoCharLater)) {
        passValid = false;
        break;
      }
    }
  if (passValid) {
    valid.push(password)
  }
})

console.log(valid)
KyleFairns
  • 2,947
  • 1
  • 15
  • 35