in reply to simple pattern match ?

A regular expression only works character by character, not token by token. So, if you want to match a two-digit number, you have to specify two characters that can match 0 through 9.

Your expression  [0-59\*] will allow the characters 0,1,2,3,4,5,9 and *, which, likely, isn't what you wanted. To match a digit between 0 and 59, or a *, you could use the following regular expression:

([012345]?\d|\*)

That is, you allow the first digit (if any) to be between 0 and 5, and then require a second digit after it, you just don't care what it is.

For matching digits between 0 and 23, it gets trickier:

([01]?\d|2[0123]|\*)

The approach is to match (optionally) a zero or one, and then any digit. If the first digit is a 2, we explicitly require a 0, 1, 2 or 3.

Is there any reason you're forced to parsing the crontab yourself? There is Schedule::Cron and some other Crontab parsers, and your regular expression does not cover the weirder (Vixie) cron extensions like */3, which allows to trigger an event every 3 units, or 1,5,7,9,11, which would trigger the event at 1 minute, 5 minutes, 7 minutes and so on.

Update: ikegami pointed out that I forgot to allow for *.

Replies are listed 'Best First'.
Re^2: simple pattern match ?
by Anonymous Monk on Mar 15, 2006 at 15:47 UTC
    Thanks. I realised after I'd posted this that it didn't handle the plethra of other extensions. I'll take a look at the CPAN modules to avoid re-inventing the wheel !
Re^2: simple pattern match ?
by McDarren (Abbot) on Mar 15, 2006 at 16:22 UTC
    To match a digit between 0 and 59, or a *, you could use the following regular expression:
    ([012345]?\d)
    Actually, that would fail on single digit entries between 0 and 5 - because the first (optional) part of the expression would match, and then there would be no 2nd digit to match the second (required) part (\d). For the sake of the exercise, I had a play around with it and the following seems to work (for 0-59):
    /^(?:[0-9*]|[12345]\d)$/
    (But I also echo your sentiments about not re-inventing the wheel)

    Cheers,
    Darren :)

      This is a quick, nasty way of matching a range without spending a lot of effort on crafting a clever regular expression.

      @range = (0 .. 59); { local $" = '|'; $rxMatchIt = qr{(@range)}; }

      You end up with a regular expression which says match 0 or 1 or ... 59. This falls over if there are leading zeros but could easily be adapted to cope. I like nifty regular expressions but sometimes quick and dirty gets the job done.

      Cheers,

      JohnGG

      On Perl 5.8.5, the pattern works for me:

      #!perl -w for (qw( 00 01 02 03 04 05 06 07 08 09 0 1 2 3 4 5 6 7 8 9 10 20 30 40 50 58 59 )) { die "Ooops: $_ didn't match the regular expression" unless /([012345]?\d)/; }; print "All numbers passed.";
        So it does :)

        So my logic above is flawed. I'm almost certain that I tested your pattern earlier and it failed - but obviously not.

        Anyway, I guess that means that the regex engine is "smart enough" to know that even if it gets a match with the [012345]? - it has to "release" it to the \d if there is no 2nd digit - yes?