Advent of Code: Day 8

Source

Part 1: Given an escaped string of the form "\xa8br\x8bjr\"", convert it to the escaped form: br js. Calculate the total difference of lengths between the former (16) and the latter (5).

memory_count = 0
raw_count = 0

for line in sys.stdin:
    raw = line.strip()
    parsed = ast.literal_eval(raw) # This is probably cheating

    raw_count += len(raw)
    memory_count += len(parsed)

print(raw_count - memory_count)

For a basic solution, we can cheat and use the ast module. It can interpret any Python literal, which includes escaped strings. Free!

If we actually want to do it ourselves, it’s straight forward enough to use regular expressions instead:

memory_count = 0
raw_count = 0

patterns = [
    (r'\\"', '"'),
    (r'\\\\', r'\\'),
    (r'\\x(\d\d)', chr),
    (r'^"(.*)"$', r'\1'),
]

for line in sys.stdin:
    parsed = raw = line.strip()
    for src, dst in patterns:
        parsed = re.sub(src, dst, parsed)

    print(raw, parsed)

    raw_count += len(raw)
    memory_count += len(parsed)

print(raw_count - memory_count)

One interesting aspect is chr. That will convert a number such as \x65 into the corresponding character A. It doesn’t really matter since we just want the count, but it’s kind of elegant.

There is a subtle bug in this, bonus points to anyone that can figure it out. But for the moment, it works great on the given test cases.

Part 2: Do the opposite. Add another level of encoding such that "\xa8br\x8bjr\"" would become \"\\xa8br\\x8bjr\\\"\".

raw_count = 0
encoded_count = 0

for line in sys.stdin:
    raw = line.strip()
    encoded = re.sub(r'(["\\])', r'\\\1', raw)

    raw_count += len(raw)
    encoded_count += len(encoded) + 2 # Quotes are not included

print(encoded_count - raw_count)

This time since we don’t have different behavior for the different escaped characters, we can use a single regular expression.

Not quite as interesting as Day 7, but still neat.