Machinarius
Machinarius

Reputation: 3731

Regex not working correctly in JS

I want to have a simple capture and test program for a specific date format (Which is not compatible with Date.parse - NaN) with this RegEx:

/(\d{1,2})\/(\d{1,2})\/(\d{2,4})/ //day/month/year

It works on the rubular tester but using it in chrome yields weird results:

dateRegex.test("19111/7/1992")
> true
"19111/7/1992".match(dateRegex) //Wrong on purpose
> ["11/7/1992", "11", "7", "1992"] //Why is it matching 11?

Is there any specific to JavaScript RegEx that i need to be aware of?

Upvotes: 0

Views: 128

Answers (4)

user13500
user13500

Reputation: 3856

The actual matching routine should be well explained by other answers.

To further validate the date you could do something like this:

function valiDate(d) {
    var v, m = d.match(/^(\d{1,2})\/(\d{1,2})\/(\d{1,4})$/);
    if (!m)
        return false;
    v = new Date(m[3], m[2] - 1, m[1]);
    return m[1] == v.getDate() &&
        m[2] == v.getMonth() + 1 &&
        m[3] == v.getFullYear()
    ;
}

Or the possibly faster:

function valiDate(d) {
    function leap(y) {
        return !((y%4)||(!(y%100) && (y%400)));   
    }
    var m = d.match(/^(\d{1,2})\/(\d{1,2})\/(\d{1,4})$/);

    //  Not match || date or month below 1, or month above 12
    if (!m || m[1] < 1 || m[2] < 1 || m[2] > 12) {
        return false;
    // Jan,Mar,May,Jul,Aug,Oct,Dec
    } else if ([2,4,6,9,11].indexOf(+m[2]) < 0) {
        return m[1] < 32;
    // Feb
    } else if (m[2] === '2') {
        return m[1] < 29 ? true :
            m[1] < 30 && leap(+m[3]);
    // Apr,Jun,Sep,Nov
    } else {
        return m[1] < 31;
    }
}

Upvotes: 1

Jason
Jason

Reputation: 13766

Your regex is behaving correctly. Specifically what's happening is the following:

19111/7/1992
   ^
   matching starts at this point, everything before that is ignored

What you need is to specify that your regex should start at the beginning of the string, and end at the end of the string:

/^(\d{1,2})\/(\d{1,2})\/(\d{2,4})$/

... note the ^ and $, these will cause any extra characters at the beginning or end to fail the regex.

Upvotes: 0

Sabuj Hassan
Sabuj Hassan

Reputation: 39443

First of all, this is not the correct way to handle date. It can parse 99/99/9999 as date. I think you are aware about this.

Now come to your question, why it parsed 11/7/1992? Because you didn't provide any boundary and it matched part of a string. You can do it in several ways.

This forces the entire string to match from end to begin with anchors(^ $).

/^(\d{1,2})\/(\d{1,2})\/(\d{2,4})$/

Using \b to boundary the numbers. This will help you to parse from the middle of any string.

/\b(\d{1,2})\/(\d{1,2})\/(\d{2,4})\b/

Upvotes: 1

Oriol
Oriol

Reputation: 288660

Try using

^(\d{1,2})\/(\d{1,2})\/(\d{2,4})$

^ asserts position at the beginning of the string, and $ asserts position at the end of string (or before the line break at the end of the string, if any).

Upvotes: 1

Related Questions