Javascript regex returning true.. then false.. then true.. etc

26,966

Solution 1

/^[^-_]([a-z0-9-_]{4,20})[^-_]$/gi;

You're using a g (global) RegExp. In JavaScript, global regexen have state: you call them (with exec, test etc.) the first time, you get the first match in a given string. Call them again and you get the next match, and so on until you get no match and it resets to the start of the next string. You can also write regex.lastIndex= 0 to reset this state.

(This is of course an absolutely terrible piece of design, guaranteed to confuse and cause weird errors. Welcome to JavaScript!)

You can omit the g from your RegExp, since you're only testing for one match.

Also, I don't think you want [^-_] at the front and back. That will allow any character at each end, ie. *plop! would be valid. You're probably thinking of lookahead/lookbehind assertions, but they're not available in JavaScript. (Well, lookahead is supposed to be, but it's broken in IE.) Suggest instead:

/^[a-z0-9][a-z0-9_-]{2,18}[a-z0-9]$/i

Solution 2

[a-z0-9-_]

This is wrong, The last - must be at the beginning or end.

[a-z0-9_-]

Whether that would cause this problem or not, I don't know.

Additional notes:

The first and last characters are allowed to be any character that isn't - or _ rather than being restricted to a-z0-9

a-z0-9 doesn't include uppercase characters. You need a-zA-Z0-9 for that. a-zA-Z0-9_ can be shortened to \w in most RegEx engines. I haven't tried it in JavaScript.

Share:
26,966
betamax
Author by

betamax

Updated on July 08, 2022

Comments

  • betamax
    betamax almost 2 years

    I have a strange problem with the validation I am writing on a form. It is a 'Check Username' button next to an input. The input default value is the username for example 'betamax'. When I press 'Check Username' it passes the regex and sends the username to the server. The server behaves as expected and returns '2' to tell the javascript that they are submitting their own username.

    Then, when I click the button again, the regex fails. Nothing is sent to the server obviously because the regex has failed. If I press the button again, the regex passes and then the username is sent to the server.

    I literally cannot figure out what would be making it do this! It makes no sense to me!

    Edit: I've tested the problem in Firefox and Chrome (mac)

    This is my code:

    $j("#username-search").click(checkUserName);
    
    function checkUserName() {
        var userName = $j("#username").val();
    
    
        var invalidUserMsg = 'Invalid username (a-zA-Z0-9 _ - and not - or _ at beginning or end of string)';
        var filter = /^[^-_]([a-z0-9-_]{4,20})[^-_]$/gi;
        if (filter.test(userName)) {
            console.log("Pass")
            $j.post(
            "/account/profile/username_check/", 
            { q: userName }, 
            function(data){
                if(data == 0) {
                    $j("#username-search-results").html("Error searching for username. Try again?");
                }
                else if(data == 5) {
                    $j("#username-search-results").html(invalidUserMsg);
                }
                else if(data == 4) {
                    $j("#username-search-results").html("Username too short or too long.");
                }
                else if(data == 2) {
                    $j("#username-search-results").html("This is already your username.");
                }
                else if(data == 3) {
                    $j("#username-search-results").html("This username is taken.");
                }
                else if(data == 1){
                    $j("#username-search-results").html("This username is available!");
                }
            });
        } else {
            console.log("fail")
            $j("#username-search-results").html(invalidUserMsg);
        }
    
        return false;
    
    }
    

    The HTML:

    <input name="username" id="username" value="{{ user.username }}" />
    <input type="button" value="Is it taken?" id="username-search">
    <span id="username-search-results"></span>
    
  • betamax
    betamax about 14 years
    Thanks for the tip. Why exactly does the order matter? Unfortunately, that didn't solve the problem I am seeing. I just tested it in chrome (was using Firefox) and it does the same thing.
  • Powerlord
    Powerlord about 14 years
    - is a special character in groups... as you can see, since you use it for a-z. Due to this, it's defined as only being a literal - as the first or last character of a RegEx. Having said that, you may need to switch it in [^-_] as well (to [^_-]).
  • Powerlord
    Powerlord about 14 years
    Whoops, I just noticed I put /w instead of \w in my answer. Should be fixed now.
  • betamax
    betamax about 14 years
    Thats it. I normally include /g out of habit but I guess I wont do that anymore! Thanks!
  • betamax
    betamax about 14 years
    I have the 'i' flag at the end of the RegEx which makes it case-insensitive. Another flaw I have noticed in the RegEx is that it accepts anything BUT - or _ at the beginning of the string (ie. betamax£ would be valid). So taking that into consideration and the fix mentioned by bobince, the final RegEx is /^[a-z0-9]([a-z0-9_-]{4,20})[a-z0-9]$/i
  • Amit Patil
    Amit Patil about 14 years
    You can alternatively use \- to put a literal hyphen anywhere in a character group. This approach is probably more readable though! Well, by regex standards... @betamax: yes, just spotted that myself and added it in! :-)
  • Jon z
    Jon z over 8 years
    I guess if you make a global regular expression with capturing groups and call test on that, it’s sort of a crazy request - what capturing group are you trying to test? Not to excuse javascript, they picked the craziest possible solution to a slightly crazy problem..
  • Ricardo Martínez
    Ricardo Martínez almost 3 years
    Here is stated developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…, thanks @bobince, I didn't knew about it :)
  • GHOST-34
    GHOST-34 almost 3 years
    If this was the answer you were looking for, it's time to learn regex.