Let's walk through your rules:
- No more than 9 characters
- 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}$"
- 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?
- 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