The WebApp Wizard Web development made magical

4Oct/111

Time input mask, RegExp powered

Hi.

I dreamed about this for a long time. An input mask which would not allow any unvalid time such as 25:63. I know we can achieve this by checking this via a function bound on keydown, but the goal here is to do this without functions, but rather just via one regular expression. We could also try to check input on blur, for instance. But that could be misleading for the user, who could enter an invalid time and only be warned at the end.

You think that's no big deal? Maybe you think it is as simple as /^[0-2][0-9]:[0-5][0-9]$/

That's where the fun begins. At the time you type the first number, this expression will never match. "1" doesn't match /^[0-2][0-9]:[0-5][0-9]$/. Remember, we want to match on each keystroke.
So here is the one that matches :

/^(([0-1][0-9]|2[0-3]|[0-9])|([0-1][0-9]|2[0-3]|[0-9])(:|h)[0-5]?[0-9]?)$/

Boom. That bulky horror only matches a simple time input. Let's try to re-build this. First, we guess we will have a problem with the separator ":" or "h" sign. It cannot be optional, but if it isn't, we cannot type the first numbers, as the regexp won't match, right? Wrong. We have to use alternatives. We can have two numbers, or two numbers followed by the separator, followed by two other numbers.

/^((\d{1,2})|(\d{1,2})(:|h)(\d{0,2}))$/
  • On first keystroke (if we type a number), the first part of the alternative will match
  • On second keystroke, the first part will still match
  • On third keystroke, the first part won't match anymore (max 2 numbers). The second part will, though, if and only if this third character is a ":" or "h" separator
  • On fourth keystroke, the second part of the alternative will match (if we type a number)
  • On fifth keystroke, the second part will also match, if we type a number

That seems to be a good start, and it is not that complex. We also note that it allows to type something like "9:54", which can be a good thing (we do not need to fill with the initial "0"). However, it is far from perfect, as we can also type something like "89:76", which not at all a legit time input. But we're gonna fix this, and that's when we make this (almost) clean expression look like a pile of garbage.

Let's focus on the hours part. We want to be able to type 8:25 as well as 02:31 and 18:58, but not 24:14 neither 16:85. This is quite simple, we can, once again, use alternatives. Either we want one digit, between 0 and 9, either we want two digits, with the first one between 0 and 2, and the second one between 0 and 9, unless the first one is 2. Wow, slow down. So, we got:

  • Any single-digit number between 0 and 9 : [0-9] (or \d)
  • Any two-digits number between 0 and 19 : [0-1][0-9] (or [0-1]\d)
  • Any two-digits number between 20 and 23 : 2[0-3]

So we've got our hour-matching regexp, with range checking:

[0-9]|[0-1][0-9]|2[0-3]

It's way simpler for the minutes, as we just want to check a two-digits number comprised between 0 and 59. Remember we want to match while the user types, so we add "?" to make minutes numbers "optional"

[0-5]?[0-9]?

Just pop that in place of our previous naive \d{1,2} and \d{0,2}, and we've got our super-regexp:

/^(([0-1][0-9]|2[0-3]|[0-9])|([0-1][0-9]|2[0-3]|[0-9])(:|h)[0-5]?[0-9]?)$/

You can use this with Ruoso's compact and efficient jQuery regexMask if you want to give it a try.

I still don't know what to think about this: the regexp is not that complex, but still complex for such a simple case. What about more complex cases, like e-mail for instance? E-mail can be checked quite easily with a regexp (and still, the real e-mail regexp is not as simple as many believe), but if we add the "on-the-fly" checking, it must begin to be quite unreadable.

But hey, a single regexp...

Comments (1) Trackbacks (2)
  1. That was the most useful wiegdt i have ever had. Can you help me please? I have a woman’s magazine blog and i installed your wiegdt. The problem is that i want to exlude some posts like fashion 2011 or swimwears 2011 because they are not useful any more. How can i exclude some posts from this amazing random posts wiegdt? (Sorry about my english. It is not my mother language)


Leave a comment

(required)

You can use basic HTML to enlighten your comments. If you want to post some code, please use the <pre> tag. You can also use syntax coloring by adding class="syntax [language]". <pre class="syntax js"> will color your code as if it was JS code for instance.