Question

I'm still learning Perl regular expressions and I need to match a string that represents the time.

However there are instances where multiple times get entered. Instead of '9AM' I will sometimes get '9AM5PM' or '09AM05PM' and so on... Fortunately, It always starts with one or two numbers and ends with 'AM' or 'PM' (Upper and Lowercase)

Here's what I have so far:

$string =~ /^((([1-9])|(1[0-2]))*(A|P)M)$/i;

Any help would be greatly appreciated!

Was it helpful?

Solution

The only problem I can see with your own code is that the hours field is optional (because you use a *) but you don't say what issues you're having.

You do have a lot of unnecessary captures. Every part of the pattern that is enclosed in parentheses will capture the corresponding part of the target string in an internal variables called $1, $2 etc. Unless you really need those captures it is best to use non-capturing parentheses (?: ... ) instead of the plain ones ( ... ).

Character classes like [1-9] are a single entity and don't need enclosing in parentheses. You also haven't accounted for a leading zero on values less than ten, and you should use a character class [AP] instead of an alternation (?:A|P)

It looks like you need

/\d{1,2}[AP]M/i

But you don't say what you want to do with the times once you have found them.

This snippet of code demonstrates the functionality by putting all the times that it finds in a string into array @times and then printing it with space separators.

use strict;
use warnings;

for my $string (qw/ 9AM 9AM5PM 09AM05PM /) {
  my @times = $string =~ /\d{1,2}[AP]M/ig;
  print "@times\n";
}

output

9AM
9AM 5PM
09AM 05PM

If you really want to verify that the hour value is in range (are you likely to come across 35pm?) then you could write

my @times = $string =~ / (?: 1[012] | 0?[1-9] ) [AP]M /igx

Note that the /x modifier makes whitespace insignificant within regular expressions, so that it can be used to clarify the form of the pattern.

OTHER TIPS

You can try something like:

$string =~ /^((0?\d|1[0-2])[AP]M)+$/i;

As you can see here. Or:

$string =~ /^((0?\d|1[0-2])[AP]M){1,2}$/i;

If you want it to be just up to 2 hours together.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top