4

I have a reminder app and I need to split the time like 3:30 a.m.. I used re module but I failed.

What I'm trying to do is split the time by colon in front of the words in list. But list has multiple words. Like a.m., am

The program should try the words until it gets the right match, and split the time by colon, such as hour and minute. 13:25 to [13, 25].

Here is an example:

import re

am = ['a.m.', 'am', 'ante meridiem']
timeinp = 'reminder for 3:30 am'

for a in am:
    gettime = re.search(fr'\b\d?\d:\d\d\b {a}', timeinp).group(0)
    gettime = re.split('[:]', gettime)
    print(gettime)

This code gives me AttributeError: 'NoneType' object has no attribute 'group'.

TylerH
  • 20,799
  • 66
  • 75
  • 101

2 Answers2

2

You may use a single regex with capturing groups to instantly get access to hours and minutes if there is a match:

import re

am = ['a.m.', 'am', 'ante meridiem']
timeinp = 'reminder for 3:30 am'

a = "|".join(map(re.escape, am))
gettime = re.search(fr'\b(\d{{1,2}}):(\d{{2}})\s*(?:{a})', timeinp)
if gettime:
    print(list(map(int, gettime.groups()))) # => [3, 30]
else:
    print("no match")

See Python demo

Note that gettime.groups() contains a tuple containing all the subgroups of the match, from 1 up to however many groups are in the pattern. The capturing groups are all those parts of the pattern enclosed with (...).

You need to re.escape your am list items, otherwise, . matches any char. You need to use \. outside a character class to match a literal dot.

Wiktor Stribiżew
  • 607,720
  • 39
  • 448
  • 563
  • Wiktor, you could have fixed the regex string by escaping the brackets. Was wondering why you decided to delete it or to use another regex – user120242 Jul 28 '20 at 15:25
  • 1
    Nothing "wrong" per se. I'm commenting about your original post that you deleted and decided to revert to the OP's version of the regex. \d{1,2} is being evaluated to "(1,2)" because of the `f` modifier – user120242 Jul 28 '20 at 15:27
  • 1
    @user120242 It makes little difference. Reverted to using `{1,2}` and `{2}` – Wiktor Stribiżew Jul 28 '20 at 15:29
  • @WiktorStribiżew How to match this `re` something like `1.5` or `.5`? –  Jul 31 '20 at 17:42
  • @June `\d+(?:\.\d+)?` – Wiktor Stribiżew Jul 31 '20 at 17:46
  • `self.hour = 'hours later, hour later'` `h = "|".join(map(re.escape, self.hour))` `gettime = re.search(fr'\b(\d+(?:\.\d+)?{{1,9}})\s*(?:{h})', self.inp)` I edited the code to get just hour, but this gives me `multiple repeat at 16` error. –  Jul 31 '20 at 17:54
  • @June `self.hour` is a string, why do you `join` it? See [this Python demo](https://ideone.com/B5w2cX) to learn how to access each group individually. – Wiktor Stribiżew Jul 31 '20 at 18:02
  • Sorry, I forgot the brackets for `self.hour`. I'm trying to get something like `3.5` or `.5` from`set reminder for a.m.` Please help. –  Jul 31 '20 at 18:07
  • @June This is now becoming unclear, I hope [this snippet](https://ideone.com/UVQVSx) will be helpful. – Wiktor Stribiżew Jul 31 '20 at 20:23
1

As others have noted, you're getting an AttributeError due to re.search() returning None in cases where an item stored in am results in no match within your loop.

The below example is similar to others in handling cases in which re.search() returns None, however it:

  • Uses a lookahead to in the pattern as to not include the am item in the match returned.
  • Further processes the match into a list of 2 int instances instead of str instances.
  • Breaks the loop following print(gettime) to stop any further iterations and keep the list value assigned to gettime available following loop execution.
  • Includes some basic logic to printout a No time match found! message for cases in which the loop exits without matching as per your criteria.
import re

am = ['a.m.', 'am', 'ante meridiem']
timeinp = 'reminder for 3:30 am'
gettime = None

for a in am:
     gettime = re.search(fr'\b\d?\d:\d\d\b(?= {a})', timeinp)
     if gettime:
            gettime = [ int(i) for i in re.split(':', gettime.group()) ]
            print(gettime)
            break
            
if not gettime:
    print('No time match found!')
JPI93
  • 1,507
  • 5
  • 10