Regular expression to accept numbers and letters, regardless of sequence

5

I have the following problem, I need to validate a password field with at least 8 characters, being at least 2 numbers and the rest letters, they can be in any position.

12abcdef abcdef12

The expression I made works in the cases above:

function vSenha(senha) {
    return /^(((?=.*[a-z])(?=.*\d{2,}).{8,16})|(?=.*\d{2,})(?=.*[a-z]).{8,16})$/.test(senha);

}

But if I put a letter and a number interspersed, the expression does not work. I was trying to mount an OR operator with regex but I did not succeed.

Ex how it does not work:

1a2b3c4d

    
asked by anonymous 14.07.2017 / 19:54

6 answers

1

After some tests the following expression solved my problem:

function vSenha(senha) {
    return /^((?=(?:.*?[a-z]){1,})(?=(?:.*?[0-9]){2,})).{8,16}$/.test(senha);
}

The following cases work:

12cbahda
1b3c4c3d2a
a1fewfew2

I did not need anything else to run the validation.

    
14.07.2017 / 20:25
4

I think it's going to be difficult for a regex to span all cases. It would be easier to go by counting the characters and numbers and check in the end.

Suggestion:

var testes = ["12abcdef", "abcdef12", "1a2b3c4d", "abcdefghij"];

function vSenha(senha) {
  var numeros = 0;
  var letras = 0;
  var caracteres = senha.split('');
  for (let car of caracteres) {
    if (car.match(/\d/)) numeros++; // se for numero
    else if (car.match(/\w/)) letras++; // se não for numero, pode ser letra
  }
  return numeros >= 2 && (numeros + letras) == senha.length;

}

testes.forEach(teste => console.log(teste, vSenha(teste)));
    
14.07.2017 / 20:07
2

I think it's simpler to use two regex one for numbers and another just for letters and then check the minimum values of each category, since the catch (with the g parameter) returns an array. I added an extra check that captures other characters like #@,._ if any of them find the password invalid.

function validarSenha(senha){

    if(senha.length === 0 || senha.match(/\W|_/)){
        console.log('senha invalida');
        return false;
    } 

    var numeros = senha.match(/\d/g) ? senha.match(/\d/g).length : 0;
    var letras = senha.match(/[a-zA-Z]/g) ? senha.match(/[a-zA-Z]/g).length : 0;
    var totalCaracteresValidos = numeros + letras;
    var tamanhoMinimoSenha = 8;


    if(totalCaracteresValidos >= tamanhoMinimoSenha && numeros >= 2 && !senha.match(/\W|_/)){
       console.log('senha valida');
    }else{
       console.log('senha invalida');
    }
}


validarSenha('12345AAAA'); //válida
validarSenha('12345AAAA#'); //invalida devido ao '#' mesmo tendo 8 mais de caracteres sendo pelo menos 2 dígitos.
validarSenha('1ABC2ccD'); //válida
    
14.07.2017 / 20:13
1

You can even set up a REGEX for this, but it would be huge, just because is not regular , since numbers can be anywhere in the password.

Ideally, you should build an algorithm like suggested by @sergio

My suggestion:

function checkPass(pass){
  var len = pass.length;
  var num = pass.replace(/\D/g, '').length;
  var wrong = pass.replace(/[a-z0-9]/gi, '').length; // REMOVE TUDO QUE VOCÊ QUER, CASO HAJA CARACTERES QUE VOCÊ NÃO QUER ELES ESTARAO AQUI.
  return len >= 8 && num >= 2 && !(wrong > 0);
}

var testes = ["12abcdef", "abcdef12", "1a2b3c4d", "abcdefghij", "1a2b$3c4d"];

for(var i=0;i<testes.length;i++){
  console.log(testes[i], checkPass(testes[i]));
}
    
17.07.2017 / 14:01
1

As already said, only with regex will be difficult to include all possibilities, in front of it, there are two ways to do this: 1st way: in this detail I will know a little more how many letters, how many numbers and how many invalid characters have been inserted.

jQuery(function($){
  jQuery('#validarSenha').click(function(){
    var senha = $('#senha').val();
    var tamanhoSenha = senha.length;
    //Verifica o tamanho da senha
    if (tamanhoSenha < 8){
      $("#ValidadeSenha").html("Senha Inválida - A senha deve conter pelo menos 8 dígitos!!");
    }
    else {
      var qtdNumeros = 0;
      var qtdLetras = 0;
      var caractereInvalido = 0;
      i = 0;
      //Percorre toda a string verificando cada caractere
      while (i < tamanhoSenha){
        //Verifica se o caractere atual é número letra
        if (senha.charAt(i).match(/\d/)) {
          qtdNumeros++; 
        }
        //Verifica se o caractere atual é letra
        else if (senha.charAt(i).match(/\w/)){
          qtdLetras++;
        }
        //Verifica se o caractere atual é um caractere que não seja letra ou número
        else{
          caractereInvalido++;
        }		
        i++;
      }

      if (qtdNumeros < 2 || caractereInvalido > 0 ){
        $("#ValidadeSenha").html("Senha Inválida - A senha deve conter pelo menos 2 números e deve conter somente letras e números!!");
        console.log("Quantidade de letras: "+qtdLetras);
        console.log("Quantidade de números: "+qtdNumeros);
        console.log("Quantidade de caracteres inválidos: "+caractereInvalido);
      }
      else {
        $("#ValidadeSenha").html("Senha válida!");
        console.log("Quantidade de letras: "+qtdLetras);
        console.log("Quantidade de números: "+qtdNumeros);
      }
    }
  });
});
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>Senha<inputtype="text" id="senha" name="senha" ><p id="ValidadeSenha"></p>
			
<br>
<button id="validarSenha" class="btn btn-warning" type="button">Validar Senha</button>

2nd Form: simpler, is basically what the @Sergio posted, but it was only the issue of validation of the minimum size of 8 digits, so the function is letting passwords with less than 8 digits, so I only completed the function of it by adding the 8 digits verification in the last line of the function:

$(document).ready(function() {
  jQuery('#validarSenha').click(function(){
    var senha = $('#senha').val();
    if (vSenha(senha) == true){
      $("#ValidadeSenha").html("Senha válida!");
    }
    else{
      $("#ValidadeSenha").html("Senha Inválida!");
    }
  });
  function vSenha(senha) {
    var numeros = 0;
    var letras = 0;
    var caracteres = senha.split('');
    for (let car of caracteres) {
      if (car.match(/\d/)) numeros++; // se for numero
      else if (car.match(/\w/)) letras++; // se não for numero, pode ser letra
    }
    return numeros >= 2 && (numeros + letras) == senha.length && senha.length >= 8;
  }
});
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>Senha<inputtype="text" id="senha" name="senha" ><p id="ValidadeSenha"></p>
			
<br>
<button id="validarSenha" class="btn btn-warning" type="button">Validar Senha</button>
    
17.07.2017 / 13:57
1

Conditions

  • 8+ characters, only numbers or letters:

    /^[a-z\d]{8,}$/i
    
  • Minimum 2 numbers:

    /^(?:.*?\d){2}/
    
  • Minimum 1 letter:

    /^.*?[a-z]/i
    

  • All together

    /^(?=.*?[a-z])(?=(?:.*?\d){2})[a-z\d]{8,}$/i
    

    To merge different conditions into the same expression, you need a Lookahead . The lookahead does not house characters at the current position, but gives a peek ahead . If the assertion matches, it returns to the current position, without consuming characters.


    Code

    function vSenha(senha) {
        var regex = /^(?=.*?[a-z])(?=(?:.*?\d){2})[a-z\d]{8,}$/i;
        return regex.test(senha);
    }
    
        
    20.07.2017 / 07:11