Bakground
So this question was inspired by the following question on codereview: Converting a string to an array of integers. Which opens as follows:
I am dealing with a string draw_result that can be in one of the following formats:
"03-23-27-34-37, Mega Ball: 13" "01-12 + 08-20" "04-15-17-25-41"I always start with draw_result where the value is one from the above values. I want to get to:
[3, 23, 27, 34, 37] [1, 12, 8, 20] [4, 15, 17, 25, 41]
This question can be solved with multiple regex expressions as follows
import re
from typing import Iterable
lottery_searches = [
re.compile(pat).match
for pat in (
r'^(\d\d)-(\d\d)-(\d\d)-(\d\d)-(\d\d), Mega Ball.*$',
r'^(\d\d)-(\d\d) \+ (\d\d)-(\d\d)$',
r'^(\d\d)-(\d\d)-(\d\d)-(\d\d)-(\d+)$',
)
]
def lottery_string_to_ints(lottery: str) -> Iterable[int]:
for search in lottery_searches:
if match := search(lottery):
return (int(g) for g in match.groups())
raise ValueError(f'"{lottery}" is not a valid lottery string')
Question
Assume that we allow a different seperator than
-but they must all be equal. For instance"04/15/17/25/41" "04,15,17,25,41" "01,12 + 08,20" "01?12 + 08?20"are all valid formats.
Is it now possible to only have the digits in capture groups? Is it possible to mark all digit capture groups in some way for easy retrieval?
Attempt at solution
Regex
PATTERN = re.compile(
r"""
(?P<digit0>\d\d) # Matches a double digit [00..99] and names it digit0
(?P<sep>-) # Matches any one digit character - saves it as sep
(?P<digit1>\d\d) # Matches a double digit [00..99] and names it digit1
(\s+\+\s+|(?P=sep)) # Matches SPACE + SPACE OR the seperator saved in sep (-)
(?P<digit2>\d\d) # Matches a double digit [00..99] and names it digit2
(?P=sep) # Matches any one digit character - saves it as sep
(?P<digit3>\d\d) # Matches a double digit [00..99] and names it digit3
((?P=sep)(?P<digit4>\d\d))? # Checks if there is a final fifth digit (-01), saves to digit5
""",
re.VERBOSE,
)
Retrieval
def extract_numbers_narrow(draw_result, digits=5):
numbers = []
if match := re.match(PATTERN2, draw_result):
for i in range(digits):
ith_digit = f"digit{i}"
try:
number = int(match.group(ith_digit))
except IndexError: # Catches if the group does not exists
continue
except TypeError: # Catches if the group is None
continue
numbers.append(number)
return numbers
- Problem: I had to include a dirty
trystatement as the fifth digit might or might not appear in the result.