5

I need help on regular expression on the condition (4) below:

  1. Begin with a-z
  2. End with a-z0-9
  3. allow 3 special characters like ._-
  4. The characters in (3) must be followed by alphanumeric characters, and it cannot be followed by any characters in (3) themselves.

Not sure how to do this. Any help is appreciated, with the sample and some explanations.

neobie
  • 2,847
  • 5
  • 27
  • 31
  • 6
    That seems rather overly-complicated! How are you going to explain the rules to the end user? – Dean Harding May 17 '10 at 05:42
  • What flavor of regexp? Perl? Javascript? Java? .Net? – T.J. Crowder May 17 '10 at 05:43
  • I've always wondered - why do developers put limits on passwords characters? I can sorta get 'must have at least this much complexity' but 'can only be this complex' muddles my brain. – Erik May 17 '10 at 05:48
  • @Erik: The OP asked for **user names**, not passwords. For user names, restrictions make a lot of sense. – Konrad Rudolph May 17 '10 at 05:50
  • possible duplicate of [How to validate a user name with regex?](http://stackoverflow.com/questions/1221985/how-to-validate-a-user-name-with-regex) – Alan Moore May 17 '10 at 05:56
  • Are you saying there can be no more than three of the separator characters? Or just that `.`, `_`, and `-` are the only three characters that can be *used* as separators? – Alan Moore May 17 '10 at 06:28

4 Answers4

9

You can try this:

^(?=.{5,10}$)(?!.*[._-]{2})[a-z][a-z0-9._-]*[a-z0-9]$

This uses lookaheads to enforce that username must have between 5 and 10 characters (?=.{5,10}$), and that none of the 3 special characters appear twice in a row (?!.*[._-]{2}), but overall they can appear any number of times (Konrad interprets it differently, in that the 3 special characters can appear up to 3 times).

Here's a test harness in Java:

    String[] test = {
        "abc",
        "abcde",
        "acd_e",
        "_abcd",
        "abcd_",
        "a__bc",
        "a_.bc",
        "a_b.c-d",
        "a_b_c_d_e",
        "this-is-too-long",
    };
    for (String s : test) {
        System.out.format("%s %B %n", s,
            s.matches("^(?=.{5,10}$)(?!.*[._-]{2})[a-z][a-z0-9._-]*[a-z0-9]$")
        );
    }

This prints:

abc FALSE 
abcde TRUE 
acd_e TRUE 
_abcd FALSE 
abcd_ FALSE 
a__bc FALSE 
a_.bc FALSE 
a_b.c-d TRUE 
a_b_c_d_e TRUE 
this-is-too-long FALSE 

See also

polygenelubricants
  • 376,812
  • 128
  • 561
  • 623
7

So basically:

  1. Start with [a-z].
  2. Allow a first serving of [a-z0-9], several times. 1)
  3. Allow
    • at most one of [._-], followed by
    • at least one of [a-z0-9]
    • three times or less.
  4. End with [a-z0-9] (implied in the above).

Which yields:

^[a-z][a-z0-9]*([._-][a-z0-9]+){0,3}$

But beware that this may result in user names with only one character.


1) (posted by @codeka)

Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
5

try that:

^[a-zA-Z](([\._\-][a-zA-Z0-9])|[a-zA-Z0-9])*[a-z0-9]$

1) ^[a-zA-Z]: beginning

2) (([._-][a-zA-Z0-9])|[a-zA-Z0-9])*: any number of either alphanum, or special char followed by alphanum

3) [a-z0-9]$

Nicolas Viennot
  • 3,921
  • 1
  • 21
  • 22
1

Well, because I feel like being ... me. One Regex does not need to rule them all -- and for one of the Nine, see nqueens. (However, in this case there are some nice answers already; I'm just pointing out a slightly different approach.)

function valid(n) {
  return (n.length > 3
    && n.match(/^[a-z]/i)
    && n.match(/[a-z0-9]$/i)
    && !n.match(/[._-]{2}/)
}

Now imagine that you only allow one ., _ or - total (perhaps I misread the initial requirements shrug); that's easy to add (and visualize):

&& n.replace(/[^._-]/g, "").length <= 1

And before anyone says "that's less efficient", go profile it in the intended usage. Also note, I didn't give up using regular expressions entirely, they are a wonderful thing.

  • You didn't state that the *only allowed* characters are `[-0-9A-Za-z._]`. So currently `aaaаааaaa` is a valid username. (Note the three cyrillic `а`s in the middle.) – Roland Illig Jun 07 '11 at 06:56