2

I am writing a PHP validation for a user registration form. I have a function set up to validate a username which uses perl-compatible regular expressions. How can I edit it so that one of the requirements of the regular expression are AT MOST a single . or _ character, but NOT allow that character at the beginning or end of the string? So for example, things like "abc.d", "nicholas_smith", and "20z.e" would be valid, but things like "abcd.", "a_b.C", and "_nicholassmith" would all be invalid.

This is what I currently have but it does not add in the requirements about . and _ characters.

function isUsernameValid()
{
    if(preg_match("/^[A-Za-z0-9_\.]*(?=.{5,20}).*$/", $this->username))
    {
        return true; //Username is valid format
    }
    return false;
}

Thank you for any help you may bring.

skcin7
  • 783
  • 1
  • 10
  • 24

3 Answers3

6
if (preg_match("/^[a-zA-Z0-9]+[._]?[a-zA-Z0-9]+$/", $this->username)) {
    // there is at most one . or _, and it's not at the beginning or end
}

You can combine this with the string length check:

function isUsernameValid() {
    $length = strlen($this->username);
    if (5 <= $length && $length <= 20
    &&  preg_match("/^[a-zA-Z0-9]+[._]?[a-zA-Z0-9]+$/", $this->username)) {
        return true;
    }
    return false;
}

You could probably do the whole lot using just one regex, but it would be much harder to read.

Bennett McElwee
  • 24,740
  • 6
  • 54
  • 63
  • This works good but it allows special characters like $. So, something like "B.andrew$man" is valid, while I only want [a-zA-Z0-9\._]. EDIT: I just read my original question and I don't think I made this distinction but I want to only allow letters and numbers. – skcin7 Jul 04 '11 at 02:37
  • @skcin7 I have edited the answer. If you could clarify what other restrictions there are, such as the length, I could simplify the two regexes. – Bennett McElwee Jul 04 '11 at 03:22
  • 1
    It might be simpler just to use a length check without using a regular expression. – Jonathan Leffler Jul 05 '11 at 01:30
  • Yes, probably combining my reg ex with a simple length check will do what you want. – Bennett McElwee Jul 05 '11 at 01:57
  • @Bennett McElwee Thank you for the help. I don't think there are any other restrictions. Length: 5-20 characters. Allowed characters: A-Z, a-z, 0-9, period, and underscore. Period and underscore cannot be at beginning or end of string and can be used AT MOST once, so "a_b.c" would be invalid. Those are the only requirements. – skcin7 Jul 06 '11 at 14:34
  • @skcin7 I have updated the answer to include the length check and the character restrictions you have described. It should do what you want now. – Bennett McElwee Jul 06 '11 at 21:51
0

You can use the following pattern, I have divided it into multiple lines to make it more understandable:

$pattern = "";
$pattern.= "%";         // Start pattern
$pattern.= "[a-z0-9]+"; // Some alphanumeric chars, at least one.
$pattern.= "[\\._]";    // Contains exactly either one "_" or one "."
$pattern.= "[a-z0-9]+"; // Some alphanumeric chars, at least one.
$pattern.= "%i";        // End pattern, optionally case-insensetive

And then you can use this pattern in your function/method:

function isUsernameValid() {
    // $pattern is defined here
    return preg_match($pattern, $this->username) > 0;
}
Emre Yazici
  • 10,136
  • 6
  • 48
  • 55
  • This would allow symbol characters like `$` as the first and last characters, which I don't think is correct. – Bennett McElwee Jul 04 '11 at 02:25
  • @Ben is there supposed to be a restriction on `$`? I don't think the original poster made such a restriction. –  Jul 04 '11 at 02:29
  • @Bennett McElwee No, it doesn't. May be you are commenting the first version of my answer. – Emre Yazici Jul 04 '11 at 02:29
  • Yes, the answer changed after I wronte my comment. :) Hmm, it looks as if this pattern doesn't check the same things as the original. I'm not sure what the original was meant to do though... – Bennett McElwee Jul 04 '11 at 02:34
  • 1
    This regex `'%[a-z0-9]+[\\._][a-z0-9]+%i'` erroneously _requires_ one dot or underscore. This should be optional. Also you need to add `^` and `$` anchors to the beginning and end. – ridgerunner Jul 05 '11 at 03:00
0

Here is a commented, tested regex which enforces the additional (unspecified but implied) length requirement of from 5 to 20 chars max:

function isUsernameValid($username) {
    if (preg_match('/                      # Validate User Registration.
        ^                                  # Anchor to start of string.
        (?=[a-z0-9]+(?:[._][a-z0-9]+)?\z)  # One inner dot or underscore max.
        [a-z0-9._]{5,20}                   # Match from 5 to 20 valid chars.
        \z                                 # Anchor to end of string.
        /ix', $username)) {
        return true;
    }
    return false;
}

Note: No need to escape the dot inside the character class.

ridgerunner
  • 33,777
  • 5
  • 57
  • 69