Reputation: 1447
I want to implement a regex for usernames with the following conditions:
The username will consist of only a-z, A-Z, 0-9 and - (hyphen);
The username shall not consist of ONLY digits or ONLY hyphens but it can have only characters;
The first & last characters shouldn't be hyphens (it can be digits but not entirely digits);
Also, there shouldn't be 2 hyphens back to back;
Minimum number of chars is 5 and max is 25;
So far I have tried this regex:
var filter = /(?=[a-zA-Z0-9-]{5,25}$)^[a-zA-Z0-9]+(-[a-zA-Z0-9]+)*$/;
It achieves conditions 1, 3, 4 and 5 correctly. But it doesn't fully satisfy condition 2. In my regex, it makes sure it doesn't consist entirely of hyphens. But it does allow only digits, which it shouldn't.
Can anyone let me know where I am going wrong or what needs to be done. Explanation of regex will be appreciated.
Upvotes: 1
Views: 2143
Reputation: 6213
This seems to work in a quick test on my computer:
^(?![^-]*--+)(?![0-9]+$)[a-zA-Z0-9][-a-zA-Z0-9]{3,23}[a-zA-Z0-9]$
Explanation
^(?![^-]*--+) No double (or more) hyphens
(?![0-9]+$) Digits only forbidden
[a-zA-Z0-9] Starts with a-z A-Z or 0-9
[-a-zA-Z0-9]{3,23} Three to 23 more characters, including hyphens
[a-zA-Z0-9]$ Ends with a-z A-Z or 0-9
So that's 1 + (3 to 23) + 1 characters, ie 5 to 25.
Upvotes: 0
Reputation: 25091
For maintainability, things like this are usually better written as a series of tests rather than one big test.
var filter = function (username) {
var allDigits = /^[0-9]+$/g,
allHyphens = /^[-]+$/g, //doesn't need a character class, but I find it's more readable
multiHyphens = /[-]+/g,
startsWith = /^[A-Za-z0-9]{1}/,
endsWith = /[A-Za-z0-9]{1}$/
hasInvalidChars = /[^A-Za-z0-9-]/,
meetsReqs = false;
if (username.length >= 5 || username.length <= 25) { //ensure correct length
meetsReqs = !allDigits.test(username);
meetsReqs = meetsReqs && !allHyphens.test(username);
meetsReqs = meetsReqs && !multiHyphens.test(username);
meetsReqs = meetsReqs && !hasInvalidChars.test(username);
meetsReqs = meetsReqs && startsWith.test(username);
meetsReqs = meetsReqs && endsWith.test(username);
}
return meetsReqs;
};
Upvotes: 5
Reputation: 71578
You can add a negative lookahead at the beginning. I also placed the ^
anchor at the beginning of the expression.
^(?![0-9]+$)(?=[a-zA-Z0-9-]{5,25}$)[a-zA-Z0-9]+(-[a-zA-Z0-9]+)*$
^^^^^^^^^^^
This prevents against a match of ^[0-9]+$
which is in other words, a string with only numbers.
Upvotes: 3