1

It seems I'm stuck with a simple regex for a password check.

What I'd like:

  • 8 up to 30 symbols (Total)
  • With any of these: [A-Za-z\d]
  • And 0 up to 3 of these: [ -/:-@[-`{-~À-ÿ] (Special list)

I took a look here and then I wrote something like:

(?=.{8,15}$)(?=.*[A-Za-z\d])(?!([ -\/:-@[-`{-~À-ÿ])\1{4}).*

But it doesn't work, one can put more than 3 of the special chars list.

Any tips?

Alex-c90
  • 13
  • 2
  • 2
    My tip would be to let the user use as many special characters as he wants – Romano Zumbé Jun 02 '17 at 08:45
  • 1
    Why do you want regex? It´s not good when it comes to count number of characters. Of course you can do it, but it´s a pain and really hard to understand or maintain. Just use some `IndexOf` or `String.Contains` and you´re done. – MakePeaceGreatAgain Jun 02 '17 at 08:51
  • @RomanoZumbé No choice. – Alex-c90 Jun 02 '17 at 08:57
  • @HimBromBeere I have to control user's inputs in my views with some JS and it seems to be the "better" solution. – Alex-c90 Jun 02 '17 at 09:00
  • Can you tell us what exactly doesn't work by providing a couple of matching and non-matching input? Should the special chars be at the end only, or anywhere? – Malte Hartwig Jun 02 '17 at 09:31
  • @MalteHartwig Yes ! Take a look here, i provided a lot use cases: https://regex101.com/r/TeLt4Q/8 – Alex-c90 Jun 02 '17 at 10:32

4 Answers4

0

Will this work?

            string characters = " -/:-@[-`{-~À-ÿ";
            string letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
            string[] inputs = {
                "AABBCCDD",
                "aaaaaaaa",
                "11111111",
                "a1a1a1a1",
                "AA@@@@AA",
                "A1C EKFE",
                "AADE   F"
                              };

            foreach (string input in inputs)
            {
                var counts = input.Cast<char>().Select(x => new { ch = characters.Contains(x.ToString()) ? 1 : 0, letter = letters.Contains(x.ToString()) ? 1 : 0, notmatch = (characters + letters).Contains(x) ? 0 : 1}).ToArray();
                Boolean isMatch = (input.Length >= 8) && (input.Length <= 30) && (counts.Sum(x => x.notmatch) == 0) && (counts.Sum(x => x.ch) <= 3);

                Console.WriteLine("Input : '{0}', Matches : '{1}'", input, isMatch ? "Match" : "No Match");
            }
            Console.ReadLine();
jdweng
  • 33,250
  • 2
  • 15
  • 20
  • Thanks for your help. I also figured out that i'll be easier in C#. And there's no need that amount of code, Regex.IsMatch() and Regex.Matches().Count would be enough :) – Alex-c90 Jun 02 '17 at 10:18
0

I would use: (if you want to stick to Regex)

var specialChars = @" -\/:-@[-`{-~À-ÿ";
var regularChars = @"A-Za-z\d";
if (Regex.Match(password,$"^(.[{regularChars}{specialChars}]{7,29})$").Success && Regex.Matches(password, $"[{specialChars}]").Count<=3))
{
  //Password OK
}

If consists of:

  1. Check Length and if password contains illegal characters

  2. Check if ony contains 3 times special char

A litle faster:

var specialChars = @" -\/:-@[-`{-~À-ÿ";
var regularChars = @"A-Za-z\d";
var minChars = 8;
var maxChars = 30;
if (password.Length >= minChars && password.Length <= maxChars && Regex.Match(password,$"^[{regularChars}{specialChars}]+$").Success && Regex.Matches(password, $"[{specialChars}]").Count<=3))
{
   //Password OK
}
RoJaIt
  • 451
  • 3
  • 10
  • Thanks for your help but the first answer doesn't work. And for the C# one, I also figured out something like that, with Lenght > 7 && < 31 :) – Alex-c90 Jun 02 '17 at 10:48
0

Newbie here..I think I've managed to get what you need but one of the test cases you shared was kinda weird..

    A@~`  C:
    OK -- Match (3 specials, it's okay)

Shouldn't this be failed because it has more than 3 specials?

Could you perhaps try this? If it works I'll type out the explanations for the regex.

https://regex101.com/r/KCL6R1/2

    (?=^[A-Za-z\d -\/:-@[-`{-~À-ÿ]{8,30}$)^(?:[A-Za-z\d]*[ -\/:-@[-`{-~À-ÿ]){0,3}[A-Za-z\d]*$
Jialer Chew
  • 349
  • 1
  • 10
0

After shuffling your regex around a bit, it works for the examples you provided (I think you made a mistake with the example "A@~` C:", it should not match as it has 6 special chars):

(?!.*(?:[ -\/:-@[-`{-~À-ÿ].*){4})^[A-Za-z\d -\/:-@[-`{-~À-ÿ]{8,30}$

It only needs one lookahead instead of two, because the length and character set check can be done without lookahead: ^[A-Za-z\d -/:-@[-`{-~À-ÿ]{8,30}$

I changed the negative lookahead a bit to be correct. Your mistake was to only check for consecutive special chars, and you inserted the wildcards .* in a way that made the lookahead never hit (because the wildcard allowed everything).

Malte Hartwig
  • 4,477
  • 2
  • 14
  • 30
  • Oh, yes, i made i mistake with the "A@~` C:" example. Sorry, i updated [the page](https://regex101.com/r/X9wH8D/4/) in order to fix it. Thanks for your answer, it works very well ! I understand the way you did it by negating the first lookahead which implements the rule "0 to 3" special characters and then just checking authorized symbols. Many thanks :) Resolved. – Alex-c90 Jun 02 '17 at 12:20
  • @Szadek35 You are welcome. I just saw that I had forgotten some parentheses in the lookahead. They are not necessary, I removed them. – Malte Hartwig Jun 02 '17 at 12:25