A user can enter a few valid date combinations into an input :
Examples : ( all combinations are allowed 3!=6)
feb 7 2012
feb 07 2012
7 feb 2012
2012 7 feb
...
All are valid dates.
I have also managed to create a regex which check it :
/^(?=.*\b(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)\b)(?=.*(\b[12]\d{3}\b))(?=.*\b(0[1-9]|[12]\d|3[01])\b).*$/i
Which means :
(?=.*\b(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)\b) : I'm expecting one of those values at the future.
(?=.*(\b[12]\d{3}\b)) : I'm expecting year : 1xxx or 2xxx
(?=.*\b(0[1-9]|[12]\d|3[01])\b) I'm expecting day : 0x or 1x or 2x or 3x
All are OK.
So where is the problem ?
My regex also matches an invalid solutions which includes a valid solution :
IE : feb 13 2012 4 will also pass.
Console :
/^(?=.*\b(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)\b)(?=.*(\b[12]\d{3}\b))(?=.*\b(0[1-9]|[12]\d|3[01])\b).*$/i.test('feb 13 2012 4') //true
Question :
How can I enhance my regex in order to find a strict match ?
p.s.
Checking new Date(xxx) is also a solution , but I'm looking for regex solution.(to improve my regex skills).
Write a regexp for each format:
RE1 - recognizes MON DD YYYY = (?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)\s+(?:0?[1-9]|[12]\d|3[01])\s+[12]\d{3}
RE2 - recognizes DD MON YYYY = (?:0?[1-9]|[12]\d|3[01])\s+(?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)\s+[12]\d{3}
RE3 - recognizes YYYY DD MON = [12]\d{3}\s+(?:0?[1-9]|[12]\d|3[01])\s+(?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)
Then combine them:
/^(?:RE1|RE2|RE3)$/i
Create one look-forward (?=...) group at the beginning, then optional groups for digits before or after the month block. The regex below works for all of your examples (see the unit tests at the linked page). Edit: it now matches all 3!=6 allowed combinations, but no impermissible combinations like 2 feb 1978 4.
/^(?=[a-z]{3}\s(\d{1,2}\s\d{4}|\d{4}\s\d{1,2})$|\d{1,2}\s[a-z]{3}\s\d{4}$|\d{4}\s[a-z]{3}\s\d{1,2}$|(\d{1,2}\s\d{4}|\d{4}\s\d{1,2})\s[a-z]{3}$)([12]\d{3}\s|\d{1,2}\s){0,2}(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)(\s\d{1,2}|\s[12]\d{3}){0,2}$/i
Debuggex Demo
Explanation:
The entire expression must look like one of the following:
Three of [a-z] followed by a day, then a year
Three of [a-z] followed by a year, then a day
A day, three of [a-z], and a year
A year, three of [a-z], and a day
A day, a year, then three of [a-z]
A year, a day, then three of [a-z]
Optionally match one or both of the number groups
Match the three-letter month code
Optionally match one or both of the number groups
Related
I want date range from 12 to 15. How to get this? Please help
let dates = ["10/07/2021", "11/07/2021", "12/07/2021", "13/07/2021", "14/07/2021", "15/07/2021", "16/07/2021", "17/07/2021"];
Remove item before 12 and after 15
newDates = ["12/07/2021", "13/07/2021", "14/07/2021", "15/07/2021"];
Alternatively (this is essentially #Bravo's suggestion in the comments / #Nithleh's answer below but using regex to make the code a little cleaner):
dates = dates.filter( date => {
let d = new Date(date.replace(/(\d{2})\/(\d{2})\/(\d{4})/, '$3-$2-$1'))
return d.getDate() >= 12 && d.getDate() <= 15
} )
// shoud return ["12/07/2021", "13/07/2021", "14/07/2021", "15/07/2021"]
Regex explanation:
\d matches single digits 0-9 (and other numerical digits). {2} specifies the length of the matching set. (..) captures groups and \/ matches the /.
Your date format is 12/07/2021. In other words, a group of 2 digits followed by a forward slash / followed by a group of 2 digits followed by a / followed by a group of 4 digits. This translates into:
(\d{2})\/(\d{2})\/(\d{4}). This captures 3 parts; first part 2 digits ($1), second part 2 digits ($2) and the third part 4 digits ($3).
Replace function takes care of formatting the date into yyyy-mm-dd format since Date requires the date string to be in that format.
Now we know that the third part $3 holds year, $2 month and $1 day. So date.replace(/(\d{2})\/(\d{2})\/(\d{4})/, '$3-$2-$1') replaces (shifts the parts) the original date 12/07/2021 with the newly formatted date 2021/07/12
Now let d = new Date(date.replace(/(\d{2})\/(\d{2})\/(\d{4})/, '$3-$2-$1')) will have a date object and d.getDate() will give the day portion.
Note that this solution d.getDate() >= 12 && d.getDate() <= 15 would only work if the dates fall within the same month of the same year OR if you want to get these particular days regardless of the month or year.
I'm trying to come up with a regex which will reject non-consecutive characters in a supplied date format. I want to be as flexible as possible, and so I have decided that my date format string can contain YY or YYYY, MM or MMM, DD or DDD, hh mm and ss.
Some of the regex I have worked out already - for example, matching the following will show that the month is a 3 character format:
([M])\1{2}
I'm totally in the dark with regard to checking that the date format doesn't contain non consecutive characters. For example, the following date formats should be valid:
YYYY-MM-DD hh:mm:ss
hh:mm:ss YYYY-MM-DD
DD/MMM/YYYYhh-mm
But these formats should be rejected
YYYY-MM-DD hh:mm:ss YYYY // year appears twice
hh:mm:ss YYYY-MM-DD hh // hour appears twice
DD/MMM/YYYYhh-mm m // m not consecutive with other m
In the interests of future expansion, I want to allow non consecutive special characters (/ - . : ) etc and reject all non-consecutive alpha-numeric characters. Case sensitive though - mm and MM are not not the same (as above)
Just to be clear - I'm not trying to validate an actual date - I am trying to validate a date format string only.
I suggest checking if there is at least one occurrence of the same character that has already been present before, and then negating the outcome:
function(text) {
return !/(\w)\1*(?!\1).*\1/.test(text);
}
See the regex demo. You may change \w to [YMDhms] to only check these six letters.
Pattern details
(\w) - Group 1 (further referenced to with the \1 backreference): a word char
\1* - zero or more occurrences of the same char as in Group 1
(?!\1) - set a boundary, make sure there next char is not the same as the char in Group 1
.* - any zero or more chars other than line break chars, as many as possible
\1 - the same char as in Group 1.
I have the following piece of javascript to compare a DD-MM-YYYY HH-MM-SS date format, but for some reason it doesn't work. Can anyone see what is wrong with it? (mind that there is a whitespace between the date & time.
new RegExp (/^(0?[1-9]|[12][0-9]|3[01])[\/\-\.](0?[1-9]|1[012])[\/\-\.](\d{4})\s([0-1][0-9]|[2][0-3]):([0-5][0-9]):([0-5][0-9])$/)
The actual data I'm matching to this regExp looks like any of the following:
1-1-2013 0:00:00
1/1/2013 0:00:00
01-01-2013 00:00:00
01/01/2013 00:00:00
31-12-2013 23:59:59
These are the max ranges. Note that from 0:00:00 till 9:59:59 the time is noted like that and for 10:00:00 it's 6 digits, preferably it would handle leap years too.
It looks like the delimiter for the time is : and not -. Try:
new RegExp (/^(0?[1-9]|[12][0-9]|3[01])[\/\-\.](0?[1-9]|1[012])[\/\-\.](\d{4})\s([0-1][0-9]|[2][0-3])\-([0-5][0-9])\-([0-5][0-9])$/)
You should keep things small and test little pieces of regex.
You want to allow one-digit for an hour, but you've forgotten to place it in your regex. It should look like that:
([0-9]|[0-1][0-9]|[2][0-3])
Now it works:
regex = new RegExp (/^(0?[1-9]|[12][0-9]|3[01])[\/\-\.](0?[1-9]|1[012])[\/\-\.](\d{4})\s([0-9]|[0-1][0-9]|[2][0-3]):([0-5][0-9]):([0-5][0-9])$/)
match = '1-1-2013 0:00:00'.match(regex)
console.log(match)
The return value for (new Date()).toDateString() is "Mon Oct 08 2012". However I can't find ANY documentation anywhere for what the abbreviations for the rest of the days of the week and months are. Are they all just 3 character abbreviations? I'm trying to write a regex.
+1million points for someone who can find the documentation, or even the source code?
Three letter abbreviations with the first letter upper case.
Months: Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec
Days: Sun, Mon, Tue, Wed, Thu, Fri, Sat
However, you may want to look into Date.Parse() instead of using a regular expression to parse the date string, depending on what you're doing anyway.
EDIT: Beware that that Date.Parse() is fairly browser dependent. Check out Why does Date.parse give incorrect results?
It's just the standard English language abbreviation for days and months. Just the first 3 letters and the first one capitalized.
From the MDN:
Date instances refer to a specific point in time. Calling toString
will return the date formatted in a human readable form in American
English
It's not hard to find:
W3Schools: http://www.w3schools.com/jsref/jsref_todatestring.asp
Mozilla Developer Network: link
Microsoft Developer Network: link
As you can see, all of them converge, its the week day, the month name, both with 3 characters, day of month and full year.
The specification does not define the output of the string:
The contents of the String are implementation-dependent, but are intended to represent the "date" portion of the Date in the current time zone in a convenient, human-readable form.
This might change in the future, but for now, each browser/environment can produce a different output.
So I was looking at how I could display a Desktop Notification using a Google Chrome extensions when I came across these lines of code:
var time = /(..)(:..)/(Date()); // The prettyprinted time.
var hour = time[1] % 12 || 12; // The prettyprinted hour.
var period = time[1] < 12 ? 'a.m.' : 'p.m.'; // The period of the day.
What the heck does all of this do?
Fascinating, I've not seen this before:
/regex/(...);
EDIT: see this!
This:
/(..)(:..)/(Date());
// seems to emulate the functionality of exec()
Will return the match (array of matched groups) of the regular expression, /(..)(:..)/, against the string (Date()):
"Thu Jul 08 2010 09:40:38 GMT+0200 (W. Europe Daylight Time)"
(or whatever time it happens to be)
The returned array (the match), in this case, is:
["09:40", "09", ":40"]
This line:
var hour = time[1] % 12 || 12;
...simply determines the hour. If the hour is falsey (i.e. 0) then it defaults to 12 -- this makes it possible for the next statement to return the correct am/pm suffix. (12:00 is am).
The first line is using a regular expression to extract the time element from the string returned by Date(). For instance, this might be '08:37' The brackets in this regular expression give two different 'groups' of characters, the first group matching '08', the second matching '37'
The second line is taking the first set of characters, which will be automatically converted to a number, and getting the remainder of division by 12. Presumably to turn a 24 hour clock number into a 12 hour clock number. '|| 12' acts to return 12 just in case the remainder is 0.
The third line uses a ternary conditional operator to add 'a.m' just in case the hour is smaller than 12, otherwise 'p.m.'