-1

I am programming a login form, and I want to use regex to validate user input as follows:

Username:

  • 5 to 16 characters in length
  • Can use upper case and lower case alphanumeric characters
  • Can use underscore, dash, and spaces, but can't use two in a row or begin or start the username with it. This is what I am using but the max length limit is not working
([a-zA-Z0-9]+([_ -]?[a-zA-Z0-9])*){5,16}

Password:

  • 8 to 16 character in length
  • At least one special character " !"#$%&'()*+,-./:;<=>?@[]^_`{|}~"
  • At least one number
  • At least one upper case character
  • At least one lower case character

This is what I have so far, but it is not working

(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[" !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~"]).{8,16}

I would appreciate your help with this one


EDIT

I am using the the pattern tag of the input element of html with regex to verify the user input on the client side, and PHP to verify the input on the server side.

I am designing the sign in/up system, if you think I should enforce different restrictions on the username and password please let me know

Thanks again

Joseph Azzam
  • 105
  • 1
  • 14
  • 1
    This would be done more easily with several patterns that each check for a single requirement. In particular, it would be easier to comprehend after some time and thus less error prone. – Imanuel Sep 27 '17 at 17:03
  • See my accepted answer here: https://stackoverflow.com/questions/29632747/regular-expression-for-password-requirements-for-pci-compliance There is no reason to do it as all one regex. – Andy Lester Sep 27 '17 at 19:27
  • @AndyLester your answer does not include min and max length. – Joseph Azzam Sep 27 '17 at 19:44
  • Splitting it into multiple pieces can also be an option, or I can just add comments – Joseph Azzam Sep 27 '17 at 19:45
  • No, my linked answer does not include all your criteria, but you can add them yourself. Besides, it's probably in the wrong language, too. The key is that it is FAR easier to work with multiple conditions rather than trying to cram them all into a given regex. – Andy Lester Sep 27 '17 at 19:46
  • Yes though I I am using this with the pattern tag of the input html element. As for adding them myself that I what I tried and failed, and came here. – Joseph Azzam Sep 28 '17 at 08:38
  • Please refer to https://stackoverflow.com/q/48345922/3600709 – ctwheels May 25 '19 at 10:57

1 Answers1

4

Brief

Since I don't know which programming language you are using, I'll present you with regex in the PCRE flavour. This allows such things as negative lookbehinds, which, you will see in the username validation.

Also, you shouldn't restrict the password length to 16.


Code

Username

See this code in use here

^(?![_ -])(?:(?![_ -]{2})[\w -]){5,16}(?<![_ -])$

Password

See this code in use here

^(?:(?=.*?\p{N})(?=.*?[\p{S}\p{P} ])(?=.*?\p{Lu})(?=.*?\p{Ll}))[^\p{C}]{8,16}$

Results

Input - Username

** VALID **
usern
username-is-writ
username is here
username_is_here


** INVALID **
user
username-is-written-here
-username
_username
 username
username-
username_
username 
username--here
username  here
username__here
username- here
username _here

Note: The 8th invalid input above has a trailing space

Output - Username

usern
username-is-writ
username is here
username_is_here

Input - Password

********** VALID **********
Password1!
TestPass###231
My Pass#123~12`1
!#$Afs1!@(*''
VDFt35q#@$@
éA1!@#!@#!

********* INVALID *********
PASSWORD1!
password1!
Password1
Password
Passw1!
ThisIsMySuperLongPassword1!
Ae!                     1

Note: The last invalid example above uses tabs (an invalid character)

Output - Password

Password1!
TestPass###231
My Pass#123~12`1
!#$Afs1!@(*''
VDFt35q#@$@
éA1!@#!@#!

Explanation

Username

  • ^ Assert position at start of line.
  • (?![_ -] Negative lookahead to ensure that the username does not begin with the characters in the set _ -
  • (?:(?![_ -]{2})[\w -]){5,16}
    • Match between 5 and 16 characters where the following format is met.
      • (?![_ -]{2}) Negative lookahead to ensure that there are no two characters in the set _ - that immediately follow each other.
      • [\w -] Match any word character (a-zA-Z0-9_) or space or -
  • (?<![_ -] Negative lookbehind to ensure that the username does not end with the characters in the set _ -
  • $ Assert position at end of line.

Password

  • ^ Assert position at start of line
  • (?:(?=.*?\p{N})(?=.*?[\p{S}\p{P} ])(?=.*?\p{Lu})(?=.*?\p{Ll})) Grouping of positive lookaheads for easier visibility, can remove non-capture group if prefered. Each positive lookahead that follows uses .*?. This will match any character any number of times, but as few as possible.
    • (?=.*?\p{N}) Positive lookahead ensuring that at least one numeric character is present.
    • (?=.*?[\p{S}\p{P} ] Positive lookahead ensuring that at least one symbol, punctuation, or space is used.
    • (?=.*?\p{Lu}) Positive lookahead ensuring that at least one uppercase letter is used.
    • (?=.*?\p{Ll}) Positive lookahead ensuring that at least one lowercase letter is used.
  • [^\p{C}]{8,16} Match any non-control character between 8 and 16 times.
  • $ Assert position at end of line.
ctwheels
  • 21,901
  • 9
  • 42
  • 77
  • Thank you so much for the prompt reply, I will test it tomorrow morning and get back to you. I have also updated the question with the requested info – Joseph Azzam Sep 27 '17 at 19:46
  • I added it to the pattern tag of the input html element, but it didn't work at all, the fields are now accepting all cases – Joseph Azzam Sep 28 '17 at 08:40
  • @JosephAzzam, I believe you are confusing *validation* and *restriction*. You are attempting to restrict the user's input, not validate it. These are 2 **completely different** animals. Your validation should **always** occur on the server, where the client no longer has control over the input. The reason for this is that anyone can view the login form's code and edit it. If you are validating on the user's side, you're opening your application up for anyone to play with it and try to break it. You need to restrict user input, but not rely on the information the user provides to be accurate. – ctwheels Sep 28 '17 at 14:13
  • @JosephAzzam Instead, you need to pass the values the user is inputting in the field to a server-side script (i.e. PHP) and then validate its input. This means that the code above should be used in a server-side programming language like PHP and it should be used to **validate** your user's input. If the above does not match, then the user has not input the username/password properly and you must then return them to the same screen and let them know that they have entered something invalid and present them with the same information you presented to us so that they can properly input values. – ctwheels Sep 28 '17 at 14:16
  • @JosephAzzam So I would suggest you use something like `[\w_ -]{5,16}` for username in HTML and `.{8,16}` for password to restrict the user to those two simple patterns and have a popup or bubble or some way of conveying information to the user explaining that the username must ... and the password must ... (as you did in your question). Then use the regex I posted above to validate those fields on the server-side. Also, I'd suggest not restricting to the specific symbols you put in your question. You should allow any symbol (non-control character) to be used. – ctwheels Sep 28 '17 at 14:21
  • Hey, thank you for the explanation, you are right, though I wanted to have restrictions on both the client and server side. After digging around yesterday trying to find the equivalent regexp for the pearl version you provided, I decided to just use PHP and ajax, that way I only need to update the regex in one place, and I don't need to worry that both languages have matching. Plus the regex will then not be visible in the html code online. Though I'm curious why I shouldn't restrict the use of some characters? – Joseph Azzam Sep 29 '17 at 08:59