Day 19
Feelings
Well. Tried to do this in Rust. Ended up learning Python.
Learnings
Found out about regex-module for Python. It supports much more versatile regexes than I've been using.
Solution (both parts)
import regex
def defs(rules_s):
for rule in rules_s.split('\n'):
n, s = rule.split(': ', 1)
s = regex.sub(r'\s*(\d+)\s*', r'(?&r\1)', s)
s = regex.sub(r'"(\w+)"', r'\1', s)
yield "(?P<r{}>{})".format(n, s)
rules_s, messages_s = open('./input').read().split("\n\n", 1)
r = regex.compile(r'(?(DEFINE){})^(?&r0)$'.format(''.join(defs(rules_s))))
print("part1:", sum(1 if r.match(msg) else 0 for msg in messages_s.split('\n')))
rules_s, messages_s = open('./input').read().split("\n\n", 1)
rules_s = regex.sub(r'8: 42', '8: 42 | 42 8', rules_s)
rules_s = regex.sub(r'11: 42 31', '11: 42 31 | 42 11 31', rules_s)
# .. or replace with what you had in the instructions page
r = regex.compile(r'(?(DEFINE){})^(?&r0)$'.format(''.join(defs(rules_s))))
print("part2:", sum(1 if r.match(msg) else 0 for msg in messages_s.split('\n')))
This whole solution bases on using regex group definitions. What are they?
Regex group definitions
>>> regex.search(
r'(?(DEFINE)(?P<quant>\d+)(?P<item>\w+))(?&quant) (?&item)',
'5 elephants')
<regex.Match object; span=(0, 11), match='5 elephants'>
And they can be recursive so even this works:
>>> regex.search(
r'(?(DEFINE)(?P<quant>\d+)(?P<ele>ele(?&ele)?)(?P<item>(?&ele)\w+))(?&quant) (?&item)',
'5 eleeleelephants')
<regex.Match object; span=(0, 17), match='5 eleeleelephants'>
This allow the conversion from rules to regex with group definitions. Every rule is a single definition and references other rules.