4

I want to create a method in java for username validation using Regex. But i am not good in Regex creation and this is a complex one. I would appreciate any of your kind help - suggestions

I want usernames to comply with those rules:

  1. No more than 9 character
  2. No less than 3 characters
  3. No special characters except underscore and hyphen ("_" and "-")
  4. Those two characters can't be the one after the other and the username can't start or end with them

I only know how to apply rule no. 3

String Regex = "^[\w-]+$";

NOTE: rules 1. and 2. aren't important for regex because I will probably do those checks with java. But I would like to know the way.

cavla
  • 118
  • 3
  • 11
  • Start here http://stackoverflow.com/questions/3802192/regexp-java-for-password-validation/3802238#3802238 – Pshemo May 03 '15 at 10:41
  • 2
    On the one hand you are asking a great question; you show what you did so far yourself; clear problem statement; but still I am wondering: do you really think that you should turn to stackover flow for this? You see, there are great tutorials on regex out there (for starters: https://docs.oracle.com/javase/tutorial/essential/regex/ ) If you want to use regular expressions in your code, then **you** should **understand** how they are built and how they work. It is never a good idea to use concepts in your code - that require you to talk to other people when there is a need for change. – GhostCat May 03 '15 at 10:42
  • @Pshemo Thank you for your reference but i have viewed this topic such as many others online but i haven't find a solution yet.Not accepted from the java engine at least. – cavla May 03 '15 at 10:47
  • This reference should give you info about idea of how you can use lookaround mechanisms to achieve your goal. Please update your question with your attempt to use these technique and describe what wrong is happening with your approach. – Pshemo May 03 '15 at 10:52
  • @Jägermeister Yes you are right, but you see i want to learn how to use regex and i am sure i will but i am still an inexperienced coder and i have lot to learn and i don't want to stall my project for this one regex i want to use.Plus i want just copy-paste the answer as you may think.I will try to understand how it worked.I already experimenting and try to find a solution for my problem with this online tool [link](https://www.debuggex.com) – cavla May 03 '15 at 10:59

2 Answers2

8

Let's walk through your rules:

  1. No more than 9 characters
  2. No less than 3 characters

These two can be grouped in the quantifier {3,9} which applies to your entire username. You already use the + quantifier which means "one or more", you can remove that one.

"^[\w\s-]{3,9}$"

  1. No special characters except underscore and hyphen ("_" and "-")

You already covered this, but note that \s means whitespace. You don't mention spaces in your question, are you sure you need those?


  1. Those two characters can't be the one after the other and the username can't start or end with them

Here it gets more tricky. You'll need lookaround assertions to enforce these rules one by one.

First let's start with "Those two characters can't be the one after the other". You can use a negative lookahead before your regex which checks that nowhere two of those are together:

(?!.*[-_]{2,})

The ?! means "the upcoming string shouldn't match the following regex" (aka negative lookahead), and [-_]{2,} means "two or more underscores/dashes".

The next part of the rule is "can't start or end with them". We could create two separate negative lookaheads for this (not starting and not ending with those characters), but as pointed out in the comments you could also combine those into one positive lookahead:

(?=^[^-_].*[^-_]$)

This says the upcoming string must (positive) match "no - or _, then any amount of characters, then again no - or _".


Combine all these lookaheads with the original regex and you get your answer:

"^(?!.*[-_]{2,})(?=^[^-_].*[^-_]$)[\w\s-]{3,9}$"

You can use this tool to test if a regex matches multiple inputs to figure out if it works correctly: http://www.regexplanet.com/advanced/java/index.html

Stephan Muller
  • 27,018
  • 16
  • 85
  • 126
  • You can merge 2 negative lookaheads into 1 positive: `(?=^[^-_].*[^-_]$)` – Wiktor Stribiżew May 03 '15 at 11:04
  • @stribizhev Thanks, I knew I overlooked something – Stephan Muller May 03 '15 at 11:06
  • Thank you so much for your answer.That was the answer.So the regex matching my needs with the addition of @stribizhev comment is "^(?!.*[-\_]{2,})(?=^[^-\_].*[^-\_]$)[\w-]{3,9}$" (yes you were right i don't want whitespaces). But i have one more question if i want to include unicode characters of an other language (which are marked as specials) how will i be able to do that? – cavla May 03 '15 at 11:27
  • I'm not very familiar with that, but this might help you: http://stackoverflow.com/questions/10894122/java-regex-for-support-unicode – Stephan Muller May 03 '15 at 11:28
  • nicely explained,+1 for the same – rocking May 03 '15 at 11:44
  • 1
    @Stephan Muller Thank you once again for your reference i found the way to do it here: [link](http://stackoverflow.com/questions/10894122/java-regex-for-support-unicode) – cavla May 03 '15 at 12:04
  • For the copy and pasters ...be aware that this allow tabs in usernames. you probably dont want that. – user368604 May 26 '20 at 09:24
2
[A-Za-z0-9_-]  # a number or letter or underscore or hyphen
{3,9}          # Length at least 3 characters and maximum length of 15
^(?![_-]).     # can't start with underscore or hyphen
(?<![-_])$     # can't end with underscore or hyphen
((?!_-|-_).)   # underscore and hyphen can't be the one after the other

So

 ^(?![_-]).[A-Za-z0-9_-]((?!_-|-_).)(?<![-_]){3,9}$

Simple demo:

package example;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

class Validator{

      private  Pattern pattern;
      private  Matcher matcher;

      private static final String USERNAME_PATTERN = 
              "^(?![_-]).[A-Za-z0-9_-]((?!_-|-_).)(?<![-_]){3,9}$";

      public Validator(){
          pattern = Pattern.compile(USERNAME_PATTERN);
      }

      /**
       * Validate username with regular expression
       * @param username username for validation
       * @return true valid username, false invalid username
       */
      public  boolean validate(final String username){

          matcher = pattern.matcher(username);
          return matcher.matches();

      }
}

public class UserNameValidator {
    public static void main(String[] args) {
          Validator v = new Validator();
          System.out.println(v.validate("cd-eh"));
      }

}

Output:

true
MChaker
  • 2,610
  • 2
  • 22
  • 38
  • Thank you for your reply.But you may reconsider the regex because if i try to validate the username "loco" it will print false though it applies all the rules and if i try to validate the username "loco_-o" the result will be true though it doesn't apply the rule #4. The working regex i came to is ^(?!.*[-\_]{2,})(?=^[^-\_].*[^-\_]$)[\w-]{3,9}$ – cavla May 03 '15 at 11:59