Last active
September 10, 2020 11:45
-
-
Save Dan6erbond/214e329c7a63cfc22ae000cdf209b425 to your computer and use it in GitHub Desktop.
A Python script to parse various time formats specifying duration.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import cProfile | |
import random | |
import re | |
units = { | |
"days": { | |
"seconds": 60 * 60 * 24, | |
"aliases": ["d"], | |
}, | |
"hours": { | |
"seconds": 60 * 60, | |
"aliases": ["h", "hr", "hrs"], | |
}, | |
"minutes": { | |
"seconds": 60, | |
"aliases": ["m", "min", "mins"], | |
}, | |
"seconds": { | |
"seconds": 1, | |
"aliases": ["s", "sec", "secs", ""], | |
}, | |
}.items() | |
RE = re.compile(r"(?:(?P<amt>\d{1,3}(?:\.\d{1,2})?)\s?(?P<unit>[a-zA-Z]*)?)") | |
def get_seconds(_input): | |
matches = RE.finditer(_input) | |
def next_match(matches): | |
try: | |
match = next(matches) | |
except BaseException: | |
return None, None | |
amt, unit = match.group("amt"), match.group("unit") | |
if not amt: | |
return next_match(matches) | |
return amt, unit | |
amt, unit = next_match(matches) | |
seconds = 0 | |
for name, config in units: | |
found = False | |
if unit == name or unit in config["aliases"]: | |
seconds += float(amt) * config["seconds"] | |
found = True | |
if amt and found: | |
amt, unit = next_match(matches) | |
elif not amt: | |
break | |
return seconds | |
def get_seconds_optimized(_input): | |
matches = list(RE.finditer(_input)) | |
index = 0 | |
seconds = 0 | |
for name, config in units: | |
amt = 0 | |
while not amt: | |
try: | |
index += 1 | |
match = matches[index] | |
amt = match.group("amt") | |
if amt: | |
unit = match.group("unit") | |
except BaseException: | |
break | |
if not amt: | |
break | |
if unit == name or unit in config["aliases"]: | |
seconds += float(amt) * config["seconds"] | |
return seconds | |
AMY_RE = re.compile(r"(?:(?P<days>\d+(?:.\d+)?)\s?(?:d|days))?\s?(?:(?P<hours>\d+(?:.\d+)?)\s?(?:h|hr|hours))?\s?(?:(?P<mins>\d+(?:.\d+)?)\s?(?:m|minutes))?\s?(?:(?P<secs>\d+(?:.\d+)?)\s?(?:s|seconds|sec)?)?") | |
def get_seconds_the_amy_way(_input): | |
match = AMY_RE.match(_input) | |
seconds = 0 | |
if match.group("days"): | |
seconds += float(match.group("days")) * 60 * 60 * 24 | |
if match.group("hours"): | |
seconds += float(match.group("hours")) * 60 * 60 | |
if match.group("mins"): | |
seconds += float(match.group("mins")) * 60 | |
if match.group("secs"): | |
seconds += float(match.group("secs")) | |
values = list() | |
for i in range(5000): | |
parts = list() | |
res = 0 | |
for name, config in units: | |
if random.random() < 0.2: | |
continue | |
amt = random.random() * 365 | |
amt_str = "{:.2f}".format(amt) | |
res += amt * config["seconds"] | |
unit_index = random.randint(0, len(config["aliases"])) | |
unit = name if unit_index == len(config["aliases"]) else config["aliases"][unit_index] | |
parts.append(amt_str + " " + unit) | |
values.append((" ".join(parts), float("{:.2f}".format(res)))) | |
pr = cProfile.Profile() | |
pr.enable() | |
correct = 0 | |
for _in, res in values: | |
r = get_seconds(_in) | |
if r is r or int(r) == int(res): | |
assert True | |
correct += 1 | |
else: | |
assert False | |
print(f"Done Ravi's way, accuracy: {int(correct / len(values) * 100)}%") | |
pr.disable() | |
pr.print_stats() | |
pr = cProfile.Profile() | |
pr.enable() | |
correct = 0 | |
for _in, res in values: | |
r = get_seconds_optimized(_in) | |
if r is r or int(r) == int(res): | |
assert True | |
correct += 1 | |
else: | |
assert False | |
print(f"Done the optimized way, accuracy: {int(correct / len(values) * 100)}%") | |
pr.disable() | |
pr.print_stats() | |
pr = cProfile.Profile() | |
pr.enable() | |
correct = 0 | |
for _in, res in values: | |
res = get_seconds_the_amy_way(_in) | |
if r is r or int(r) == int(res): | |
assert True | |
correct += 1 | |
else: | |
assert False | |
print(f"Done the Amy way, accuracy: {int(correct / len(values) * 100)}%") | |
pr.disable() | |
pr.print_stats() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment