I have the fallowing problem,
Im supposed to get user input in the form of 10:10:10
(hh:mm:ss) or 10:10
(mm:ss) or 10
(ss). Now i need check the fallowing parameters:
mm:ss
then the seconds are limited to 0..59 and minutes are unlimited.hh:mm:ss
then both seconds and minutes are limited to 0..59 while hours are unlimited.Then return a TimeDelta object.
The naive way is to write multiply if
statements to check all this.
But im looking for a smoother way.
val = "11:66:11"
try:
val = map(int, val.split(':'))
except ValueError:
return False
if len(val) == 1:
return val
if len(val) == 2:
if val[1] > 59:
print "Bad seconds"
return False
if len(val) == 3:
if val[2] > 59 or val[1] >59:
print "Bad seconds / minutes"
return False
while len(val) < 3:
split.insert(0,0)
return = timedelta(hours=split[0],minutes=split[1],seconds=split[2])
How about using regular expression here:
import re
import datetime
pattern = re.compile(r'^(\d+)(?::([0-5]?\d)(?::([0-5]?\d))?)?$')
def str2seconds(val):
match = pattern.match(val)
if not match:
raise ValueError("Invalid input: %s" % val)
else:
result = 0
for i in match.groups():
if i is not None:
result *= 60
result += int(i)
return datetime.timedelta(seconds=result)
Example:
>>> print(str2seconds('255'))
0:04:15
>>> print(str2seconds('255:25'))
4:15:25
>>> print(str2seconds('255:25:25'))
10 days, 15:25:25
>>> print(str2seconds('255:25:25:255'))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "y.py", line 8, in str2seconds
raise ValueError("Invalid input: %s" % val)
ValueError: Invalid input: 255:25:25:255
>>> print(str2seconds('255:25:60'))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "y.py", line 8, in str2seconds
raise ValueError("Invalid input: %s" % val)
ValueError: Invalid input: 255:25:60
The regular expression part by part:
^
: beginning of string(\d+)
: 1-n digits, captured as group 1(?::([0-5]?\d)(?::([0-5]?\d))?)?
optional part:
(?:...)
is a non-capturing group:
matches literal :
([0-5]?\d)
an optional digit 0-5, followed by a digit, captured as group 2(?::([0-5]?\d))?
that optionally matches second :
followed by
an optional digit 0-5 followed by a digit; and capturing the digits into group 3$
matches the end of the string. Strictly, ^
at the beginning is not necessary as match
anchors the match at the beginning; however the $
is necessary, as otherwise the match is not anchored at the end of the string! (Python 3.4 added the re.fullmatch
to fix this.)The match.groups()
will be a tuple of 3 items; the non-matching groups will be returned as None
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With