optional character in Regular Expression - php

I've found this REGEXP:
^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$
It's useful to validate a date in this format:
yyyy-mm-dd
with "-" as separator. It's perfect for me except that I'd like to make this:
1970-1-1
valid too, so I'm looking for a modification to have the zero optional in month and day block as first char. Could you please provide me some help?

If you want to have an optional zero, you can this RegEx (edited version of your own):
^[0-9]{4}-((?:0)?[1-9]|1[0-2])-((?:0)?[1-9]|[1-2][0-9]|3[0-1])$
To make a character ( or a range) optional in RegEx, put it in a parenthesis followed by a question mark:
[a-z] is mandatory
([a-z])? is optional, with capturing group
(?:[a-z])? without capturing group, just optional
Read more on Capturing group in RegEx

You could use something like so: ^[0-9]{4}-(([1-9])|(0[1-9]|1[0-2]))-(([1-9])|(0[1-9]|[1-2][0-9]|3[0-1]))$.
An example is available here.

Use your current regex just make the 0 optional 0?
^[0-9]{4}-(0?[1-9]|1[0-2])-(0?[1-9]|[1-2][0-9]|3[0-1])$
DEMO

PHP already has a construct to extract dates; if you're using a regex to extract the date instead, "Now you have two problems"
PHP's DateTime::createFromFormat: "Returns new DateTime object formatted according to the specified format"
You can use it's d or j option to accept 1 or 2 digit days and it's m or n option to accept 1 or 2 digit months.
The format you'll want to use is: "Y-m-d"

Related

Preg match a string to ensure it has the 'YmdTH:i:s' date structure [duplicate]

I want to match dates with format mm/dd/yy or mm/dd/yyyy but it should not pick 23/09/2010 where month is 23 which is invalid nor some invalid date like 00/12/2020 or 12/00/2011.
Better than a crazy huge Regex (assuming this is for validation and not scanning):
require 'date'
def valid_date?( str, format="%m/%d/%Y" )
Date.strptime(str,format) rescue false
end
And as an editorial aside: Eww! Why would you use such a horribly broken date format? Go for ISO8601, YYYY-MM-DD, which is a valid international standard, has a consistent ordering of parts, and sorts lexicographically as well.
You'd better do a split on / and test all individual parts. But if you really want to use a regex you can try this one :
#\A(?:(?:(?:(?:0?[13578])|(1[02]))/31/(19|20)?\d\d)|(?:(?:(?:0?[13-9])|(?:1[0-2]))/(?:29|30)/(?:19|20)?\d\d)|(?:0?2/29/(?:19|20)(?:(?:[02468][048])|(?:[13579][26])))|(?:(?:(?:0?[1-9])|(?:1[0-2]))/(?:(?:0?[1-9])|(?:1\d)|(?:2[0-8]))/(?:19|20)?\d\d))\Z#
Explanation:
\A # start of string
(?: # group without capture
# that match 31st of month 1,3,5,7,8,10,12
(?: # group without capture
(?: # group without capture
(?: # group without capture
0? # number 0 optionnal
[13578] # one digit either 1,3,5,7 or 8
) # end group
| # alternative
(1[02]) # 1 followed by 0 or 2
) # end group
/ # slash
31 # number 31
/ # slash
(19|20)? #numbers 19 or 20 optionnal
\d\d # 2 digits from 00 to 99
) # end group
|
(?:(?:(?:0?[13-9])|(?:1[0-2]))/(?:29|30)/(?:19|20)?\d\d)
|
(?:0?2/29/(?:19|20)(?:(?:[02468][048])|(?:[13579][26])))
|
(?:(?:(?:0?[1-9])|(?:1[0-2]))/(?:(?:0?[1-9])|(?:1\d)|(?:2[0-8]))/(?:19|20)?\d\d)
)
\Z
I've explained the first part, leaving the rest as an exercise.
This match one invalid date : 02/29/1900 but is correct for any other dates between 01/01/1900 and 12/31/2099
Or you simply use Date.parse "some random date".
You'll get an ArgumentException if it fails parsing (=> Date is invalid).
See e.g. http://santoro.tk/mirror/ruby-core/classes/Date.html#M000644
The best you can do with a regexp is to validate the format, e.g. something like:
[0-1][0-9]/[0-3][0-9]/[0-9]{2}(?:[0-9]{2})?
Anything beyond that cannot be reliably done without some kind of date dictionary. A date's validity depends on whether it's a leap year or not, for instance.
For MM-DD-YYYY you could use the below regex. It'll work for leap years, and will match correct dates only unless the year doesn't exceed 2099.
(?:(09|04|06|11)(\/|-|\.)(0[1-9]|[12]\d|30)(\/|-|\.)((?:19|20)\d\d))|(?:(01|03|05|07|08|10|12)(\/|-|\.)(0[1-9]|[12]\d|3[01])(\/|-|\.)((?:19|20)\d\d))|(?:02(\/|-|\.)(?:(?:(0[1-9]|1\d|2[0-8])(\/|-|\.)((?:19|20)\d\d))|(?:(29)(\/|-|\.)((?:(?:19|20)(?:04|08|12|16|20|24|28|32|36|40|44|48|52|56|60|64|68|72|76|80|84|88|92|96))|2000))))
Checkout matches in http://regexr.com/
so you want a regex that will match as mm/dd/yy
^((0?1?1){1}|(0?1?2){1}|([0]?3|4|5|6|7|8|9))\/((0?1?2?3?1){1}|(0?1?2?(2|3|4|5|6|7|8|9|0))|(30))\/[1-90]{4}$
this regex will match exactly what you want in that format mm/dd/yy an will not validate any fake date you can test the regex on regex101
you can test for the dates 12/30/2040 and 09/09/2020 and what ever you want for that format i think this is also the shortest regex you can find for that format
Here's the code than you can use :), try it and tell me :
^([0-2][0-9]|(3)[0-1])(\/)(((0)[0-9])|((1)[0-2]))(\/)\d{4}$

Regex to check a valid number in a format in PHP

I want to check if the string is in the following format
YYMMDD-XXXX
YYYYMMDD-XXXX
YYMMDDXXXX
YYYYMMDDXXXX
I have this regex
^\d{6,8}(-\d{4})?$
But then I am stuck. I am really new at regex. Can I get some help or some pointers?
Make the - optional and your regex works:
^\d{6,8}(-?\d{4})?$
https://regex101.com/r/uoF1HM/1/
This also would match many number formats though. Your example strings look like dates, if that is the case I'd use something stricter ( or already written e.g. https://stackoverflow.com/a/14566624/3783243 might be a good place to start).
You can use this function:
function checkFunc($value){
if (preg_match('/^[0-9]{6,8}(-?)[0-9]{4}$/', $value)) {
//is valid
return $value;
} else {
//is invalid
return false;
}
}
echo checkFunc("20180529-4444"); //20180529-4444
but for the first part of string, you will have to create different check for the date format
In your regex ^\d{6,8}(-\d{4})?$ youy have an optional group (-\d{4})? with a hyphen inside the group. That means that you can only match a format like \d{6,8} or with a hyphen \d{6,8}-\d{4} but not \d{6,8}\d{4} because the hyphen should be there according to the optional group.
If you want to match your values without any capturing groups you could make only the dash optional ?
That would match
^ Assert position at the start of the line
\d{6,8} Match 6 - 8 digits
-? Match optional dash
\d{4} Match 4 digits
$ Assert position at the end of the line
^\d{6,8}-?\d{4}$

Replace Date format in a string provided using regular expression

I am trying to change a string which may have a date inside e.g.
"This is the test string with 22/12/2012. 23/12/12 could anywhere in the string"
I need to change above string so that date are in the format d-m-y i.e.
"This is the test string with 22-12-2012. 23-12-12 could appear anywhere in the string"
EDIT:
Please note that the date will could changed in terms of years i.e. 2012 or 12 could be used at time i.e 20/06/2012, 20/06/12. Only year could be 2 or 4 digits, rest will be same.
Any help will be highly appreciated.
Cheers,
Use preg_replace like this:
$repl = preg_replace('~(\d{2})/(\d{2})/(\d{2,4})~', '$1-$2-$3', $str);
Live Demo: http://ideone.com/7HDNZa
$string = preg_replace("/([0-9]{2})\/([0-9]{2})\/([0-9]{2,4})/", "$1-$2-$3", $string);
The regex will find 3 lots of 2 numbers (or 2x2 + 1x4) separated by /'s and replace them with the same numbers separated by -'s.
You could try something like this:
preg_replace('~\b([0-2]?[1-9]|3[01])/(0?[1-9]|1[0-2])/(?=(?:\d\d|\d{4})\b)~', '$1-$2-', $str);
Should match valid dates only. Does match dates where the prefix 0 is not present, e.g. 4/16/13 if this is not desierable, remove the two first question marks (in [0-2]? and 0?)

PHP Dynamic Regular expression?

I'm relativly new to regular expressions but I managed to create a working expression to validate dates (without leap years, and assuming people enter a valid 30 or 31 digit for a month).
This is the expressen:
/^\d[1-31]{2}\-\d[1-12]{2}\-\d[1900-2009]{4}$/
But I would like to have a dynamic regular expression like:
$yearSpan = (date("Y") - 110)."-".date("Y");
/^\d[1-31]{2}\-\d[1-12]{2}\-\d[$yearSpan]{4}$/
When I try to use this expression it keeps telling me the compilation failed because a range out of order in character class.
I'm using this expression to validate dates of birth, and it would be nice not to update it every time a year passes by.
Any suggestions?
I think you should consider using some date/time functions for this purpose.
You're using the character classes in wrong way. [1-31], [1-12] and [1900-2009] will not check for the ranges you have in them. That's not how character classes work and hence that's not how you check for numeric ranges with regex.
A character class [a-r] matches any char from a to r. [a-rx] matches any character from a to r and the character x. Similarly, [1-39] matches any character from 1 to 3 and the character 9 - hence it matches one of 1,2,3 and 9 - and not any number from 1 to 39 as you intended it to.
[1-31]{2} matches two consecutive numbers (the last 1 is redundant), both in the range 1 to 3 - 33 is a valid match.
To match a number from 1 to 31, the correct regex is 0?[1-9]|[1-2][0-9]|3[0-1]. ('0?' takes care of zero padding as in 01-09-2009
For months: 0?[1-9]|1[0-2]
For year: 19[0-9]{2}|200[0-9]
And - is not a meta character outside character classes - you need not escape it.
The correct regex would be:
/^(0?[1-9]|[1-2][0-9]|3[0-1])-(0?[1-9]|1[0-2])-(19[0-9]{2}|200[0-9])$/
If you are not interested in capturing the values, you can write it as:
/^(?:0?[1-9]|[1-2][0-9]|3[0-1])-(?:0?[1-9]|1[0-2])-(?:19[0-9]{2}|200[0-9])$/
You can do it with PHP date and time functions
http://php.net/manual/en/function.checkdate.php

Regular Expression to match dates in YYYY-MM-DD format

I have a regular expression in PHP that looks for the date in the format of YYYY-MM-DD
What I have is: [\d]{4}-[\d]{2}-[\d]{2}
I'm using preg_match to test the date, the problem is that 2009-11-10 works, but 2009-11-1033434 works as well. It's been awhile since I've done regex, how do I ensure that it stops at the correct spot? I've tried doing /([\d]{4}-[\d]{2}-[\d]{2}){1}/, but it returns the same result.
Any help would be greatly appreciated.
What you need is anchors, specifically ^ and $. The former matches the beginning of the string, the latter matches the end.
The other point I would make is the [] are unnecessary. \d retains its meaning outside of character ranges.
So your regex should look like this: /^\d{4}-\d{2}-\d{2}$/.
^20[0-2][0-9]-((0[1-9])|(1[0-2]))-([0-2][1-9]|3[0-1])$
I added a little extra check to help with the issue of MM and DD getting mixed up by the user. This doesn't catch all date mixups, but does keeps the YYYY part between 2000 and 2029, the MM between 01 and 12 and the DD between 01 and 31
How do you expect your date to be terminated ?
If an end-of-line, then a following $ should do the trick.
If by a non-digit character, then a following negative assertion (?!\d) will similarly work.
you're probably wanting to put anchors on the expression.
i.e.
^[\d]{4}-[\d]{2}-[\d]{2}$
note the caret and dollar sign.
You probably want look ahead assertions (assuming your engine supports them, php/preg/pcre does)
Look ahead assertions (or positive assertions) allow you to say "and it should be followed by X, but X shouldn't be a part of the match). Try the following syntax
\d{4}-\d{2}-\d{2}(?=[^0-9])
The assertion is this part
(?=[^0-9])
It's saying "after my regex, the next character can't be a number"
If that doesn't get you what you want/need, post an example of your input and your PHP code that's not working. Those two items can he hugely useful in debugging these kinds of problems.
[\d]{4}-[\d]{2}-[\d]{2}?
where the question mark means "non-greedy"
You could try putting both a '^' and a '$' symbol at the start and end of your expression:
/^[\d]{4}-[\d]{2}-[\d]{2}$/
which match the start and the end of the string respectively.

Categories