<jupyter_start><jupyter_text>Part 2<jupyter_code>all_passports = []

f = open(INPUT_PATH / "day04_input.txt", "r")
passport = {}

for i, line in enumerate(f):
    if len(line) > 1:
        fields = line.split(" ")
        for f in fields:
            key, value = f.split(":")
            value = value.rstrip()
            
            if value.isnumeric() and key not in ["pid"]:  # passport id has leading zeros
                value = int(value)
                
            passport[key] = value
    else:
        all_passports.append(passport)
        passport = {}
else:
    all_passports.append(passport)
def valid_number(x, lower, upper):
    try:
        x = int(x)
        return x >= lower and x <= upper
    except:
        return False


def valid_height(x):
    if type(x) == int:
        return False
    if x.endswith("in"):
        return valid_number(int(x[:-2]), 59, 76)
    elif x.endswith("cm"):
        return valid_number(int(x[:-2]), 150, 193)
    else:
        return False


def check_passport(p):
    re_exp = "^(#)([a-f0-9]{6})$"

    if not valid_number(p["byr"], 1920, 2002):
        return False
    elif not valid_number(p["iyr"], 2010, 2020):
        return False
    elif not valid_number(p["eyr"], 2020, 2030):
        return False
    elif not valid_height(p["hgt"]):
        return False
    elif re.fullmatch(re_exp, p["hcl"]) is None:
        return False
    elif p["ecl"] not in ["amb", "blu", "brn", "gry", "grn", "hzl", "oth"]:
        return False
    elif len(p["pid"]) != 9:
        return False
    else:
        return True
all_passports[0]
check_passport(all_passports[0])
valid_count = 0
valid_count_with_exception = 0

for p in all_passports:
    if set(p.keys()) == set(required_fields) and check_passport(p):
        valid_count += 1
        valid_count_with_exception += 1
    elif set(p.keys()) == set(required_fields_with_exception) and check_passport(p):
        valid_count_with_exception += 1
        
print("Valid passports:", valid_count)
print("Valid passports with no cid:", valid_count_with_exception)<jupyter_output>Valid passports: 72
Valid passports with no cid: 145
{'fraction_non_alphanumeric': 0.1330834114339269, 'fraction_numerical': 0.026241799437675725, 'mean_word_length': 2.558333333333333, 'pattern_counts': {'":': 1, '<': 5, '<?xml version=': 0, '>': 6, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '1', 'dir': 'jupyter-structured-clean-dedup', 'id': '174284', 'license': 'MIT', 'n_tokens_mistral': 769, 'n_tokens_neox': 710, 'n_words': 186, 'path': 'day04.ipynb', 'repo_name': 'Anjum48/advent-of-code-2020', 'size': '2134'}