How to determine which characters can enter the input?

Asked

Viewed 1,959 times

3

I have a login form and I have to limit the input to receive characters with the following conditions:

  • A capital letter
  • A number
  • A Special Character
  • A minimum of 8 characters
  • Special characters can only be these: @#$ (Most important)

OBS: I already made the filters in the PHP file, which receives this data from form login, but would like to do this also directly to us inputs to ensure.

I always get complicated when I try to use pattern. If you can give me a practical solution, I’d appreciate it.

Below is the code of my two login buttons:

<form action="" method="post" id="formulario-login-sistema">

  <div class="form-group">
    <label for="login">Usuário:</label>
    <input class="form-control" type="text" id="login" name="login" placeholder="Usuário" required autofocus />
  </div>

  <div class="form-group">
    <label for="senha">Senha:</label>
    <input class="form-control" type="password" id="senha" min="10" name="senha" placeholder="Senha" required />
  </div>


  <input class="btn btn-success" type="submit" name="enviar" value="Enviar">

</form>

If you can do it without Javascript, even better.

I almost got it using the code below:

<input class="form-control" type="password" id="senha" name="senha" placeholder="Senha" pattern="(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?=.*\W+)(?=^.{8,50}$).*$" required />

However, there is releasing all the special characters and I would just like to release these 3: @#$.

  • I almost managed using this: <input class="form-control" type="password" id="password" name="password" placeholder="Password" Pattern="(?=.[A-Z])(?=.[a-z])(?=.[0-9])(?=.\W+)(?= . {8,50}$). *$" required />. But this way it allows the entry of any special character. And I’d just like to allow the special characters (@#$).

3 answers

3


Your answer came close. But according to the documentation, the regular expression used in the attribute pattern must be a valid regex in Javascript. So I ran a test with your regex:

let r = /(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?=.*[@-#-$])(?=^.{8,50}$).*$/;

I tested the above code in Chrome, and gave this error:

Uncaught SyntaxError: Invalid regular expression: /(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?=.*[@-#-$])(?=^.{8,50}$).*$/:
Range out of order in character class

That is, the regex is invalid. The problem is that the documentation says that if regex is invalid, the attribute pattern is ignored. Therefore, when using it in HTML, the error goes unnoticed.

The problem is in the section that checks the special characters: the hyphens in [@-#-$] cause the error. Within brackets, hyphens have special meaning, as they serve to define a range (such as [a-z], defining an interval of a to z).

Only that the breaks accept any characters, then the regex interprets the passage @-# as the interval between characters @ and #. And if you look at ascii table, will see that the # comes before the @, then the range is invalid (this is what the error message says: "Range out of order"). It’s like I tried to use [z-a], which is invalid because the a comes before the z in the ASCII table (see).

So the first thing to do is to remove these hyphens and leave only the characters you want to check.

Then I also recommend putting the bookmark ^ at the beginning of the expression. This is better because of the lookaheads (the passages that begin with (?=), since they check if something exists and then return to where it was. Using ^ before them, I guarantee that the search for characters always occurs at the beginning of the string.

Without the ^, regex can repeat searches several times (first starting at the beginning of the string, then starting from the second character, and so on). This is a problem for invalid strings, because regex takes longer to realize that it is invalid: see here that without the ^ it takes more than 160 steps to realize that the string is invalid. Already using ^ she takes only 34 steps - The exact amount of steps can vary according to the size of the string, and of course for small strings it won’t have as much difference in performance, but anyway it’s a simple optimization and I prefer to do it. In addition, the use of ^, together with the $ (meaning the end of the string), also ensures that the string will only have what is in regex.

Another detail is the .{8,50} (between 8 and 50 characters). The dot corresponds to any character, so your password may be, for example, Abc123@! (see). Notice that it has the character !, and this is perfectly valid, since the Lookahead (?=.*[@#$]) only requires that there be at least one of @#$, but the dot accepts any other characters (so .{8,50} also accepts the !).

If you want the password to have only letters, numbers and @#$, simply change the regex to:

/* deixa uma borda vermelha enquanto o campo estiver inválido */
input:invalid {
    border: 1px solid red;
}
<form>
  <label for="senha">Senha:</label>
  <input type="password" id="senha" name="senha" placeholder="Senha"
   pattern="^(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?=.*[@#$])[a-zA-Z0-9@#$]{8,50}$" required />
</form>

At the beginning we have ^ (string start), and then we have the lookaheads, each checking whether there is a certain character type (uppercase, lowercase, digit or one of the characters @#$). Each Lookahead checks if a character type exists and returns to where it was (in this case, the beginning of the string), and then continues to evaluate the rest of the expression.

Instead of the point, I use [a-zA-Z0-9@#$], which makes regex no longer accept ! (or any other character that is not between the brackets). Now she only accepts what is in this list: letters, numbers or @#$. And the quantifier {8,50} indicates the minimum (8) and maximum (50) of these characters.

Recalling that the [a-zA-Z0-9@#$] alone does not require it to have at least an uppercase letter, a lowercase letter, a number and a special character. It only requires the characters to be any of the characters in this list, so if I used only that and the password only had several letters A, it would be valid (see). To force each character type to exist (letters, numbers, etc), the lookaheads.

2

I believe I got it using the following code:

<div class="form-group">
  <label for="senha">Senha:</label>
  <input class="form-control" type="password" id="senha" name="senha" placeholder="Senha" pattern="(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?=.*[@-#-$])(?=^.{8,50}$).*$" required />
</div>

In this case, the field must have at least one uppercase letter, one lowercase, one number and one special character that is one of those three (@#$). It should also have a minimum of 8 and a maximum of 50 characters.

If anyone has any reservations or anything to add, just comment.

  • 3

    The problem is that the point accepts anything, so .* accepts other special characters besides @#$. There are other things to pack too, take a look at my answer for more details :-)

0

To limit example: Username: <input type="text" name="usrname" maxlength="10"><br> For special features try this: pattern="[@-#]+"

  • 1

    I understood its placement. But what I would wish was for it to meet those specifications I quoted. Not that I want the code ready. But I would like to know how I apply those conditions within a Pattern.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.