Im currently working in a grails project and I ended up to a problem regarding matches constraints in grails. My field should only accept a String with a date-like format exactly like this:
10-25-2012 5:00PM
Is this possible in matches constraint using regex? I'm always having a hard time in data filtering using regex cause it's a little bit confusing.
If it's a data, why not to validate it using standard date formatter? Like:
static constraints = {
mydate validator: {
try {
Date.parse('MM-dd-yyyy hh:mma', it)
return true
} catch (ParseException e) {
return false
}
}
}
Btw, at this case Date can parse not so valid dates (and transform it to correnct value, like 15am to 3pm). If you need exactly valid format, your can compare it with original value:
static constraints = {
mydate validator: {
try {
Date date = Date.parse('MM-dd-yyyy hh:mma', it)
return Date.format('MM-dd-yyyy hh:mma', date) == it
} catch (ParseException e) {
return false
}
}
}
Or you can use SimpleDateFormat instead:
final static DateFormat DATEFORMAT = new SimpleDateFormat('MM-dd-yyyy hh:mma')
static constraints = {
mydate validator: {
try {
Date date = DATEFORMAT.parse(it)
return DATEFORMAT.format(date) == it
} catch (ParseException e) {
return false
}
}
}
Is there no Date object you can use? I don't know, but I can help you with the regex:
Constructing a regex is not difficult and especially in your case straight forward:
^\d{2}-\d{2}-\d{4} \d{2}:\d{2}[AP]M$
^ Matches the start of the string
$ Matches the end of the string
\d is a digit
{2} is a quantifier that makes the previous character required 2 times
[AP] is a character class that matches A or P
This regex just checks the format, not if the digits represent a valid Date or Time! (e.g. 99-99-0000 35:61PM is valid)
Read my Blog post What absolutely every Programmer should know about regular expressions for some more brief information.
Try this one: ^(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])-((?:19|20)\d\d) ([0-1]?[0-9]|2[0-4]):([0-5][0-9])(?::([0-5][0-9]))?(AM|PM)$
^ Start of string
(0[1-9]|1[012]) Month
-
(0[1-9]|[12][0-9]|3[01]) Day
-
((?:19|20)\d\d) Year
([0-1]?[0-9]|2[0-4]) HH
:
([0-5][0-9]) MM
(?::([0-5][0-9]))? optional :SS
(AM|PM)
$ End of string
It captures month, day, year, hours, minutes, seconds and AM/PM.
Edit: As Vikas points out it does not check how many days a month can have.
Try this
\b(?:(?:(?:0?[469]|11)\-(?:0?(?:[1-9]|[12][0-9])|30)\-(?:1[7-9][0-9]{2}|200[0-9]|201[0-2]))|(?:(?:0?[13578]|1[02])\-(?:0?(?:[1-9]|[12][0-9])|3[01])\-(?:1[7-9][0-9]{2}|200[0-9]|201[0-2]))|(?:(?:0?2)\-(?:0?(?:[1-9]|1[0-9])|2[0-8])\-(?:1[7-9][0-9]{2}|200[0-9]|201[0-2]))) +(?:(?:(?:0?([0-9])|1[0-2])):(?:0?([0-9])|[1-5][0-9])(?:[AP]M))\b
or
\b(?:(?:(?:0?[469]|11)\-(?:0?(?:[1-9]|[12][0-9])|30)\-(?:1[7-9][0-9]{2}|200[0-9]|201[0-2]))|(?:(?:0?[13578]|1[02])\-(?:0?(?:[1-9]|[12][0-9])|3[01])\-(?:1[7-9][0-9]{2}|200[0-9]|201[0-2]))|(?:(?:0?2)\-(?:0?(?:[1-9]|1[0-9])|2[0-9])\-(?:1[7-9][0-9]{2}|200[0-9]|201[0-2]))) +(?:(?:(?:0?([0-9])|1[0-2])):(?:0?([0-9])|[1-5][0-9])(?:[AP]M))\b
Note: Two patterns both have a common limitation that it would match invalid dates if the month is february. If-else conditionals are accepted in some RegEx flavors but there is no such functions exist for arithmatic operations. May be in far or near future this could be implemented in some RegEx flavors, but I think this not the case for what RegEx is basically is.
First pattern would not find any date greater than 28 from month of February. And it would never match any invalid date.
Second is exactly the same as above, but for it the number is 29.
And I am well-known about the fact that this issue could not entirely solved by using RegEx.
Related
I want to allow users to input a time in a masked text box and then validate that time and convert it if necessary for later saving.
I've tried a method of validating the time using only regex but honestly could not find very detailed answers. I decided to simply separate the string the user inputs into its base components and then convert the chunks of time into integers for easy comparison.
'''
Public Function CreateTimeString(TheTime As String, TheSuffix As String) As String 'wip
Dim Hour As String = "00"
Dim Minute As String = "00"
Dim inthour As Integer
Dim intminute As Integer
Dim pattern As String = "(?<hour>\d*?):(?<minute>\d*?)"
For Each m As Match In Regex.Matches(TheTime, pattern)
Hour = m.Groups("hour").Value
Minute = m.Groups("minute").Value
Next
inthour = Convert.ToInt32(Hour)
intminute = Convert.ToInt32(Minute)
TxtMeals.Text = Hour & ":" & Minute
End Function
'''
An error occurs when attempting to convert Minute string into an integer. Commenting this out and testing shows the Hour has been successfully converted. It appears that Minute cannot be found.
Example strings:
12:12
1:23
4:55
10:45
Also, if I change pattern by adding a space just before the last quotation mark neither are found and I would like to know why.
The m.Groups("minute").Value will not be found because you are using a non greedy match for \d*? for the minutes part there is no end boundary set like for example $ so it will match at least as possible which will be 0 times.
You could use:
(?<hour>\d+):(?<minute>\d+)
You might use a more precise match, for example for 12 hour time use:
(?<hour>1[0-2]|0?[1-9]):(?<minute>[0-5][0-9])
Or 24h time:
(?<hour>[01]?[0-9]|2[0-3]):(?<minute>[0-5][0-9])
You might opt to use anchors ^ and $ to assert the start and the end of the string.
Regex demo | vb.net demo
I wanted to make a regex such that the following date can be matched and its elements passed to another function:
"21Feb14"
Now the problem is the first two digits. The user can write a date in which the 'day' field is one-digit long OR two-digit long:
"21feb14" and "1jan13"
both are valid inputs.
the regex I made looks like this:
val reg = """(\\d)([a-zA-Z][a-zA-Z][a-zA-Z])(\d\d)""".r
It clearly does not take into consideration that the first digit may or may not exist. How do I handle that?
? marks handles that. Like this,
(\d?\d)([a-zA-Z][a-zA-Z][a-zA-Z])(\d\d)
But I suggest you use following regex
(\d?\d)([a-zA-Z]{3})(\d\d)
Or with posix
(\d?\d)([\p{Alpha}]{3})(\d\d)
This one is far more readable and maintainable
val reg = """(\d{1,2})([a-zA-Z]{3})(\d{2})""".r
Explanations here : http://regex101.com/r/uZ9qI5
Can anybody help me with a regex? I have a string with digits like:
X024123099XYAAXX99RR
I need a regex to check if a user has inserted the correct information. The rule should have also a fallback that the input is checked from left to right.
For example, when tested these inputs should return TRUE:
X024
X024123099X
X024123099XYA
X024123099XYAAXX99R
And these ones should return FALSE:
XX024
X02412AA99X
X024123099XYAAXX9911
And so on. The regex must check for the correct syntax, beginning from the left.
I have something like that, but this seems not to be correct:
\w\d{0,12}\w{0,6}\d{0,2}\w{0,2}
Big thanks for any help (I'm new to regex)
You could take OpenSauce's regex and then hack it to pieces to allow partial matches:
^[A-Z](\d{0,9}$|\d{9}([A-Z]{0,6}$|[A-Z]{6}(\d{0,2}$|\d{2}([A-Z]{0,2}$))))
It's not pretty but as far as I can tell it encodes your requirements.
Essentially I took each case of something like \d{9} and replaced it with something like (\d{0,9}$|\d{9}<rest of regex>).
I added ^ and $ because otherwise it will match substrings in an otherwise invalid string. For example, it will see an invalid string like XX024 and think it is okay because it contains X024.
If I understand you correctly, your strings should match the regex
[A-Z]\d{9}[A-Z]{6}\d{2}[A-Z]{2}
but you also want to check if a string could be a prefix of a matching string, is that correct? You might be able to express this in a single regex, but I can't think of a way to do so that's easy to read.
You haven't said which language you're using, but if your language gives you a way to tell if the end of the input string was reached while checking the regex, that would give you an easy way to get what you want. E.g. in java, the method Matcher.hitEnd tells you whether the end was reached, so the below code:
static Pattern pattern = Pattern.compile( "[A-Z]\\d{9}[A-Z]{6}\\d{2}[A-Z]{2}" );
static Matcher matcher = pattern.matcher( "" );
public static void main(String[] args) {
String[] strings = {
"X024",
"X024123099X",
"X024123099XYA",
"X024123099XYAAXX99R",
"XX024",
"X02412AA99X",
"X024123099XYAAXX9911"
};
for ( String string : strings ) {
out.format( "%s %s\n", string, inputOK(string) ? "OK" : "not OK" );
}
}
static boolean inputOK(String input) {
return matcher.reset(input).matches() || matcher.hitEnd();
}
gives output:
X024 OK
X024123099X OK
X024123099XYA OK
X024123099XYAAXX99R OK
XX024 not OK
X02412AA99X not OK
X024123099XYAAXX9911 not OK
We've become fairly adept at generating various regular expressions to match input strings, but we've been asked to try to validate these strings iteratively. Is there an easy way to iteratively match the input string against a regular expression?
Take, for instance, the following regular expression:
[EW]\d{1,3}\.\d
When the user enters "E123.4", the regular expression is met. How do I validate the user's input while they type it? Can I partially match the string "E1" against the regular expression?
Is there some way to say that the input string only partially matched the input? Or is there a way to generate sub-expressions out of the master expression automatically based on string length?
I'm trying to create a generic function that can take any regular expression and throw an exception as soon as the user enters something that cannot meet the expression. Our expressions are rather simple in the grand scheme of things, and we are certainly not trying to parse HTML :)
Thanks in advance.
David
You could do it only by making every part of the regex optional, and repeating yourself:
^([EW]|[EW]\d{1,3}|[EW]\d{1,3}\.|[EW]\d{1,3}\.\d)$
This might work for simple expressions, but for complex ones this is hardly feasible.
Hard to say... If the user types an "E", that matches the begining but not the rest. Of course, you don't know if they will continue to type "123.4" or if they will just hit "Enter" (I assume you use "Enter" to indicate the end of input) right away. You could use groups to test that all 3 groups match, such as:
([EW])(\d{1,3})(\.\d)
After the first character, try to match the first group. After the next few inputs, match the first AND second group, and when they enter the '.' and last digit you have to find a match for all 3 groups.
You could use partial matches if your regex lib supports it (as does Boost.Regex).
Adapting the is_possible_card_number example on this page to the example in your question:
#include <boost/regex.hpp>
// Return false for partial match, true for full match, or throw for
// impossible match
bool
CheckPartialMatch(const std::string& Input, const boost::regex& Regex)
{
boost::match_results<std::string::const_iterator> what;
if(0 == boost::regex_match(Input, what, Regex, boost::match_default | boost::match_partial))
{
// the input so far could not possibly be valid so reject it:
throw std::runtime_error(
"Invalid data entered - this could not possibly be a match");
}
// OK so far so good, but have we finished?
if(what[0].matched)
{
// excellent, we have a result:
return true;
}
// what we have so far is only a partial match...
return false;
}
int main()
{
const boost::regex r("[EW]\\d{1,3}\\.\\d");
// The input is incomplete, so we expect a "false" result
assert(!CheckPartialMatch("E1", r));
// The input completely satisfies the expression, so expect a "true" result
assert(CheckPartialMatch("E123.4", r));
try{
// Input can't match the expression, so expect an exception.
CheckPartialMatch("EX3", r);
assert(false);
}
catch(const std::runtime_error&){
}
return 0;
}
Is there an existing solution to create a regular expressions dynamically out of a given date-time format pattern? The supported date-time format pattern does not matter (Joda DateTimeFormat, java.text.SimpleDateTimeFormat or others).
As a specific example, for a given date-time format like dd/MM/yyyy hh:mm, it should generate the corresponding regular expression to match the date-times within the specified formats.
I guess you have a limited alphabet that your time formats can be constructed of. That means, "HH" would always be "hours" on the 24-hour clock, "dd" always the day with leading zero, and so on.
Because of the sequential nature of a time format, you could try to tokenize a format string of "dd/mm/yyyy HH:nn" into an array ["dd", "/", "mm", "/", "yyyy", " ", "HH", ":", "nn"]. Then go ahead and form a pattern string from that array by replacing "HH" with "([01][0-9]|2[0-3])" and so on. Preconstruct these pattern atoms into a lookup table/array. All parts of your array that are not in the lookup table are literals. Escape them to according regex rules and append them to you pattern string.
EDIT: As a side effect for a regex based solution, when you put all regex "atoms" of your lookup table into parens and keep track of their order in a given format string, you would be able to use sub-matches to extract the required components from a match and feed them into a CreateDate function, thus skipping the ParseDate part altogether.
If you are looking for basic date checking, this code matches this data.
\b(0?[1-9]|[12][0-9]|3[01])[- /.](0?[1-9]|1[012])[- /.](19|20)?[0-9]{2}\b
10/07/2008
10.07.2008
1-01/2008
10/07/08
10.07.2008
1-01/08
Code via regexbuddy
SimpleDateFormat already does this with the parse() method.
If you need to parse multiple dates from a single string, start with a regex (even if it matches too leniently), and use parse() on all the potential matches found by the regex.
The below given js / jQuery code is for dynamically generated RegEx for the Date format only, not for DateTime (Development version not fully tested yet.)
Date Format should be in "D M Y".
E.g.
DD-MM-YY
DD-MM-YYYY
YYYY-MM-DD
YYYY-DD-MM
MM-DD-YYYY
MM-DD-YY
DD/MM/YY
DD/MM/YYYY
YYYY/MM/DD
YYYY/DD/MM
MM/DD/YYYY
MM/DD/YY
Or other formats but created with "D M Y" characters:
var dateFormat = "DD-MM-YYYY";
var order = [];
var position = {"D":dateFormat.search('D'),"M":dateFormat.search('M'),"Y":dateFormat.search('Y')};
var count = {"D":dateFormat.split("D").length - 1,"M":dateFormat.split("M").length - 1,"Y":dateFormat.split("Y").length - 1};
var seprator ='';
for(var i=0; i<dateFormat.length; i++){
if(["Y","M","D"].indexOf(dateFormat.charAt(i))<0){
seprator = dateFormat.charAt(i);
}else{
if(order.indexOf(dateFormat.charAt(i)) <0 ){
order.push(dateFormat.charAt(i));
}
}
}
var regEx = "^";
$(order).each(function(ok,ov){
regEx += '(\d{'+count[ov]+'})'+seprator;
});
regEx = regEx.substr(0,(regEx.length)-1);
regEx +="$";
var re = new RegExp(regEx);
console.log(re);
NOTE: There is no validation check for months / days
e.g. month should be in 01-12 or date should be in 01-31