121

I'm trying to create a regular expression to validate usernames against these criteria:

  1. Only contains alphanumeric characters, underscore and dot.
  2. Underscore and dot can't be at the end or start of a username (e.g _username / username_ / .username / username.).
  3. Underscore and dot can't be next to each other (e.g user_.name).
  4. Underscore or dot can't be used multiple times in a row (e.g user__name / user..name).
  5. Number of characters must be between 8 to 20.

This is what I've done so far; it sounds it enforces all criteria rules but the 5th rule. I don't know how to add the 5th rule to this:

^[a-zA-Z0-9]+([._]?[a-zA-Z0-9]+)*$
5
  • no , just one occurrence of underscore or dot is allowed each time Commented Aug 18, 2012 at 12:15
  • but a_b_c_d_e would be valid right? Commented Aug 18, 2012 at 12:51
  • yes , It is . I'm testing your Regular expression now , sounds working fine :) Commented Aug 18, 2012 at 12:54
  • Can there be more than one dot if separated by non-dots? i.e. "A.B.C" (same question for underscore?) Commented Aug 18, 2012 at 13:25
  • The syntax highlighting (if it can be called that) is non-broken in this example and actually provide some value. For this case, on Stack Overflow, the default is probably taken from the ASP.NET tag ("Code Language" (whatever that means - probably effectively, without hints, regular expressions will highlighted as C#)). Commented Nov 29, 2023 at 3:03

12 Answers 12

448
^(?=.{8,20}$)(?![_.])(?!.*[_.]{2})[a-zA-Z0-9._]+(?<![_.])$
 └─────┬────┘└───┬──┘└─────┬─────┘└─────┬─────┘ └───┬───┘
       │         │         │            │           no _ or . at the end
       │         │         │            │
       │         │         │            allowed characters
       │         │         │
       │         │         no __ or _. or ._ or .. inside
       │         │
       │         no _ or . at the beginning
       │
       username is 8-20 characters long

If your browser raises an error due to lack of negative look-behind support, use the following alternative pattern:

^(?=[a-zA-Z0-9._]{8,20}$)(?!.*[_.]{2})[^_.].*[^_.]$
Sign up to request clarification or add additional context in comments.

12 Comments

@ridgerunner - I believe this way it is easy to read and port to code.
@vigneshkumar - same meaning, but [a-zA-Z0-9._] is easy to read and understand
the < in (?<![_.])$ causes a parsing error for me "invalid regular expression"
@JacksonLenhart - What regex engine and programming language you use? Please note this question was tagged with asp.net tag and while the answer is valid for most of other languages and engines, not all support negative lookahead and lookbehind zero-length assertions.
Please note that this regular expression causes an Angular app to crash on IOS devices, as well as on the Firefox browser.
|
17

As much as I love regular expressions, I think there is a limit to what is readable.

So I would suggest

new Regex("^[a-z._]+$", RegexOptions.IgnoreCase).IsMatch(username) &&
!username.StartsWith(".") &&
!username.StartsWith("_") &&
!username.EndsWith(".") &&
!username.EndsWith("_") &&
!username.Contains("..") &&
!username.Contains("__") &&
!username.Contains("._") &&
!username.Contains("_.");

It's longer, but it won't need the maintainer to open expresso to understand.

Sure you can comment a long regex, but then whoever reads it has to rely on trust.

2 Comments

What is that in? C#?
@PeterMortensen Yes, it's .NET to be specific. The RegexOptions Enum comes from the System.Text.RegularExpressions namespace
16

I guess you'd have to use Lookahead expressions here. http://www.regular-expressions.info/lookaround.html

Try

^[a-zA-Z0-9](_(?!(\.|_))|\.(?!(_|\.))|[a-zA-Z0-9]){6,18}[a-zA-Z0-9]$

[a-zA-Z0-9] an alphanumeric THEN (

_(?!\.) a _ not followed by a . OR

\.(?!_) a . not followed by a _ OR

[a-zA-Z0-9] an alphanumeric ) FOR

{6,18} minimum 6 to maximum 18 times THEN

[a-zA-Z0-9] an alphanumeric

(First character is alphanum, then 6 to 18 characters, last character is alphanum, 6+2=8, 18+2=20)

3 Comments

Try: ^[a-zA-Z0-9](_(?!(\.|_))|\.(?!(_|\.))|[a-zA-Z0-9]){6,18}[a-zA-Z0-9]$
Yup, this one works. But the (_|\.) expression can be streamlined to just [_.].
Nice, if somebody need such a RegEx for JS, this is the way. It works in all browsers unlike the most voted answer that's Chrome-only
9

A slight modification to Phillip's answer fixes the latest requirement of allowing a single instance of . or _ between letters:

^[a-zA-Z0-9]([._](?![._])|[a-zA-Z0-9]){6,18}[a-zA-Z0-9]$

1 Comment

This gives issue in character limit rule, with the given rule of {6,18} it accepts min 8 characters whereas it must be accepting 6, If I make it {4,18} then it will accept 6 characters whereas I have defined 4
4
private static final Scanner scan = new Scanner(System.in);

public static void main(String[] args) {
    int n = Integer.parseInt(scan.nextLine());
    while (n-- != 0) {
        String userName = scan.nextLine();
        String regularExpression = "^[[A-Z]|[a-z]][[A-Z]|[a-z]|\\d|[_]]{7,29}$";
        if (userName.matches(regularExpression)) {
            System.out.println("Valid");
        } else {
            System.out.println("Invalid");
        }
    }
}

1 Comment

An explanation would be in order.
3
^(?=.{4,20}$)(?:[a-zA-Z\d]+(?:(?:\.|-|_)[a-zA-Z\d])*)+$

You can test the regex here.

4 Comments

This is allowing underscore at the beginning and at the end, which is not wanted.
It also matches infinite length string that contains only underscore.
@Toto, I fixed it.
Works fine, but allows - character, I made a little adjustment to it here: ^(?=.{4,20}$)(?:[a-zA-Z\d]+(?:[._][a-zA-Z\d])*)+$ which fix it for me, thanks for the code @FrEqDe
2

I stumbled upon this question in another one, and it seems not necessary to use that many lookarounds. Following a bit shorter pattern with use of \w which is a short for word character and commonly preset to [A-Za-z0-9_]. To get rid of the underscore, [^\W_] can be used to match [A-Za-z0-9].

^[^\W_](?!.*?[._]{2})[\w.]{6,18}[^\W_]$
  • ^[^\W_] one letter or digit at the start
  • (?!.*?[._]{2}) negative lookahead to disallow __ ._ _. ..
    (for reduing steps on longer inputs, a lazy quantifier is used in .*?)
  • [\w.]{6,18} 6 to 18 characters that can be letters, digits, _ and .
  • [^\W_]$ ending in another letter or digit

See this demo at regex101 (a further explanation is on the right side)

Note: \w, depending on environment/settings, can further contain Unicode letters and digits.

Comments

1

^[a-z0-9_-]{3,15}$

^ # Start of the line

[a-z0-9_-] # Match characters and symbols in the list, a-z, 0-9, underscore, hyphen

{3,15} # Length at least 3 characters and maximum length of 15

$ # End of the line

Comments

0

This one should do the trick:

if (Regex.IsMatch(text, @"
    # Validate username with 5 constraints.
    ^                          # Anchor to start of string.
    # 1- only contains alphanumeric characters , underscore and dot.
    # 2- underscore and dot can't be at the end or start of username,
    # 3- underscore and dot can't come next to each other.
    # 4- each time just one occurrence of underscore or dot is valid.
    (?=[A-Za-z0-9]+(?:[_.][A-Za-z0-9]+)*$)
    # 5- number of characters must be between 8 to 20.
    [A-Za-z0-9_.]{8,20}        # Apply constraint 5.
    $                          # Anchor to end of string.
    ", RegexOptions.IgnorePatternWhitespace))
{
    // Successful match
} else {
    // Match attempt failed
} 

Comments

0
const regex = /^moe_(app|lab)[A-Za-z0-9]{3}$/;
const str = `moe_app_baa`;
let m;

if ((m = regex.exec(str)) !== null) {
    // The result can be accessed through the `m`-variable.
    m.forEach((match, groupIndex) => {
        console.log(`Found match, group ${groupIndex}: ${match}`);
    });
}

2 Comments

Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.
OP is using ASP.NET. While that doesn't preclude them from using JavaScript, it's ideal if answers that deviate from the OP's specified language explicitly say so, and provide justification for it.
0

Err, sorry, I generated this from my own library and it uses the syntax valid for Dart/JavaScript/Java/Python, but anyway, here goes:

(?:^)(?:(?:[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKlMNOPQRSTUVWXYZ0123456789]){1,1})(?!(?:(?:(?:(?:_\.){1,1}))|(?:(?:(?:__){1,1}))|(?:(?:(?:\.\.){1,1}))))(?:(?:(?:(?:[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKlMNOPQRSTUVWXYZ0123456789._]){1,1})(?!(?:(?:(?:(?:_\.){1,1}))|(?:(?:(?:__){1,1}))|(?:(?:(?:\.\.){1,1}))))){6,18})(?:(?:[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKlMNOPQRSTUVWXYZ0123456789]){1,1})(?:$)

My library code:

var alphaNumeric = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "l", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"];
var allValidCharacters = new List.from(alphaNumeric);
allValidCharacters.addAll([".", "_"]);

var invalidSequence = (r) => r
  .eitherString("_.")
  .orString("__")
  .orString("..");

var regex = new RegExpBuilder()
  .start()
  .exactly(1).from(alphaNumeric).notBehind(invalidSequence)
  .min(6).max(18).like((r) => r.exactly(1).from(allValidCharacters).notBehind(invalidSequence))
  .exactly(1).from(alphaNumeric)
  .end()
  .getRegExp();

My library: https://github.com/thebinarysearchtree/RegExpBuilder

1 Comment

And "abcdefghijklmnopqrstuvwxyz" can't be expressed in a more compact form?
-3
function isUserName(val){
    let regUser=/^[a-zA-Z0-9](_(?!(\.|_))|\.(?!(_|\.))|[a-zA-Z0-9]){6,18}[a-zA-Z0-9]$/;
    if(!regUser.test(val)){
      return 'Name can only use letters,numbers, minimum length is 8 characters';
    }
  }

1 Comment

An explanation would be in order.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.