4

Here's the pattern I'm working on:

var re = /(\d{1,2}\.(?=\d{1,2}))/;

What I would like for this to return is a one or two digit number (which will never be greater than 24, since it is for a time mgmt app), which may or may not be followed by a decimal point with either one or two trailing digits, but not more than two.

I'm not sure about the parenthetical substring match mixed with the lookahead. I just guessed and nested them. Ultimately, if my syntax is okay, I think the only thing I am missing is how to suggest that the pattern may or may not have leading digits, and may or may not contain a decimal with trialing digits.

Let me know if you need more info.

Update, Examples:

We are only dealing with time, and no more time than can occur in a single day. 24 would be the highest input.

Valid:

23.75
1.4 
1
0.5 
0
.2

Invalid:

1.897
%#$#@$#
Words
other characters

Newest Update:

Since this is a decimal, 23.75 works. We are not counting minutes, but rather fractions of hours.

Also, for the record, I tried validating using methods and conditionals, and it was letting letters pass through after the decimals. I have made the decision to go with regex.

eightArmCode
  • 175
  • 1
  • 4
  • 15
  • 1
    Can you give a couple of examples of the output you want to get for a particular input? And are you sure the separator is always a `.` and never say `:`? If the input is `123.456` what would you like to happen? – Floris Jun 25 '13 at 14:01
  • I updated the entry with examples. – eightArmCode Jun 25 '13 at 14:07
  • 1
    why use regex for this – Anirudha Jun 25 '13 at 14:21
  • What do you want to do with 12.345? Is it valid, invalid, do you truncate it to 12.34 or round it to 12.35? How can you be sure that the number will not be greater than 24, yet it might be a string? What do you want to do about `12.89PM`? How about `12,45` (which is how Europeans would write `12.45`) – Floris Jun 25 '13 at 14:32

3 Answers3

14

If "any number given will be less than 24", so that doesn't need to be separately tested for, then the following expression will work.

^\d{0,2}(\.\d{0,2}){0,1}$

See http://rubular.com/r/YDfHr5T5sQ

Tested against:

23.75             pass
1.4               pass
1                 pass
0.5               pass
0                 pass
.2                pass
1.897             fail
%#$#@$#           fail
Words             fail
other characters  fail

Explanation:

^             start matching at the start of the string
\d{0,2}       look for zero to two digits
(   ){0,1}$   look for this next thing zero or one time, then the end of the string
\.\d{0,2}     match exactly one decimal followed by up to two digits

Note - this regex does match the "empty string". You might want to test for that separately if there's a chance that will somehow make its way to this expression...

Simple code to test in your javascript:

var str = "12.345";
var m = str.match(/^\d{0,2}(?:\.\d{0,2}){0,1}$/);
var goodTime;
if (!m) {
    alert(str + " is not a good time");
}
else {
    goodTime = m[0];
    alert("found a good time: " + goodTime);
}

Note - I made a tweak to the regex - adding ?: in the "bit after the decimal" group. This just means "match but don't capture" so the result will return only the match m[0] and not the group .34 in m[1]. It doesn't actually matter since I assign goodTime the value in m[0] (but only if it's a good time). You can see this in action here

Floris
  • 45,857
  • 6
  • 70
  • 122
  • I will check for empty, null, undefined, etc, elsewhere. Once the string is validated and typed as a double, there are other checks I have to do. I have to play around with this, but I think this will work. ty – eightArmCode Jun 25 '13 at 15:38
  • So, the execution of this pattern match would look like this: var validFloat = timeInput.replace(re, $1); ?? (I am still trying to understand the 2nd and third parameters of .replace() ) – eightArmCode Jun 25 '13 at 16:47
  • I played around with var validFloat = timeInput.replace(re, "$1"); to no avail. It's returning an empty string. Can anyone help with the needed parameters? (Please tell me like I don't know anything, because I'm learning!) – eightArmCode Jun 25 '13 at 16:54
  • 1
    You don't try to replace - just match: `var str = "12.34"; var m = str.match(/^\d{0,2}(\.\d{0,2}){0,1}$/);` . `m[0]` will contain the match - if one exists. Otherwise it will be empty. – Floris Jun 25 '13 at 16:56
  • 1
    I have updated my answer with a "tell you like you don't know anything" bit at the end... Don't worry we have all been there. Let me know if it's now clear and solved - in which case you might decide to "accept" one of the answers given (with the little check mark). – Floris Jun 25 '13 at 17:08
  • If you are still following this, I ran into a problem and thought you might be able to help. Ultimately, it is finding two possible matches with the entry 2.15. First one is 2.15, and the second is .15. Is there a way to indicate that if a number preceeds the decimal that it should be included? – eightArmCode Jun 25 '13 at 19:50
  • 1
    Are you using the latest version of my code (updated 2 hours ago) - the "simple code to test in your Javascript"? The variable `goodTime` should have just the right answer in it... Two tricks - I changed the expression very slightly (added `?:`) and explicitly access `m[0]` for the answer. – Floris Jun 25 '13 at 20:07
  • 1
    Cannot upvote this one enough! Thanks for the solution and the cool site `Rubular` – Pierre Aug 27 '14 at 11:35
0

Well you can try this regex

^(?![3-9]\d|[2][5-9]|24[.])\d{1,2}([.]\d{1,2})?$

But you don't need to use regex here,just parse the string to number and check if it's less than or equal to 24

Anirudha
  • 32,393
  • 7
  • 68
  • 89
0

What about this one:

([1]?[0-9])|((20)|(21)|(22)|(23)|(24)){0,1}([.][0-9]{0,2})?

Edit: I would advise you to do only simple checks in RegEx and test semantic correctness (eg. less than 24) somewhere else as it gets really complicated. Time would also not allow 23:74 but 23:59...

da maddin
  • 149
  • 1
  • 3