You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Advent of Code第4天护照验证任务:如何避免重复使用if语句调用字段验证函数

解决Advent of Code第4天的护照验证代码优化问题

嗨,针对你遇到的「不想用一堆if判断来调用不同字段验证函数」的问题,最优雅的解决方案是用字典映射字段到对应的验证函数,这样既简洁又易于维护。先理清楚你的需求和现有代码,再给出具体的实现:

需求回顾

你需要完成两步护照验证:

  1. 检查数据包是否包含除cid外的所有必填字段(byr、iyr、eyr、hgt、hcl、ecl、pid)
  2. 验证每个字段的取值符合规则(你已经编写了对应的验证函数)

现有代码

你已经实现了各个字段的验证逻辑,如下:

def check_fields(list):
    comparison_list = ['byr', 'iyr', 'eyr', 'hgt', 'hcl', 'ecl', 'pid']
    statement = True
    for i in comparison_list:
        statement = statement and (i in list)
    return statement

def check_byr_iyr_eyr(line):
    prefix,value = line.split(':')
    cases = {'byr':{'min':1920, 'max':2002}, 'iyr':{'min':2010, 'max':2020}, 'eyr':{'min':2020, 'max':2030} }
    return cases[prefix]['min'] <= int(value) <= cases[prefix]['max']

def check_hgt(line):
    unit = line[len(line)-2] + line[len(line)-1]
    value = line[line.index(':')+1: -2]
    cases = {'cm':{'min':150, 'max':193}, 'in':{'min':59, 'max':76}}
    return cases[unit]['min'] <= int(value) <= cases[unit]['max']

def check_hcl(line):
    statement = True
    if line[line.index(':')+1] != '#' or len(line[line.index(':')+2:]) != 6:
        return False
    else:
        string = line[line.index('#')+1:]
        for i in string:
            statement = statement and (97 <= ord(i) <= 102 or 48 <= ord(i) <= 57)
        return statement

def check_ecl(line):
    comparison_list = ['amb', 'blu', 'brn', 'gry', 'grn', 'hzl', 'oth' ]
    if line[line.index(':') + 1:] in comparison_list:
        return True
    return False

def check_pid(line):
    if len(line[line.index(':')+1:]) != 9:
        return False
    try:
        int(line[line.index(':')+1:])
        return True
    except:
        return False

核心优化:字段-验证函数映射字典

我们可以创建一个字典,将每个必填字段直接关联到对应的验证函数,这样无需写一堆if判断,直接通过字段名查找函数即可。具体实现如下:

1. 创建映射字典

首先定义一个字典,把每个字段和它的验证函数绑定:

field_validators = {
    'byr': check_byr_iyr_eyr,
    'iyr': check_byr_iyr_eyr,
    'eyr': check_byr_iyr_eyr,
    'hgt': check_hgt,
    'hcl': check_hcl,
    'ecl': check_ecl,
    'pid': check_pid
}

这里byr、iyr、eyr共享同一个验证函数,直接映射过去就好。

2. 修改数据包处理逻辑

接下来修改读取文件和验证的代码,利用这个映射字典来简化验证流程:

line_list = []
valid_passports = 0

with open('results.txt', 'r') as f:
    for line in f:
        stripped_line = line.strip()
        if stripped_line:
            # 将当前行的字段拆分后添加到当前数据包列表
            line_list.extend(stripped_line.split())
        else:
            # 处理当前数据包
            valid_passports += process_passport(line_list)
            # 重置列表,准备下一个数据包
            line_list = []
    # 处理文件末尾没有换行的最后一个数据包
    if line_list:
        valid_passports += process_passport(line_list)

print(f"有效护照数量:{valid_passports}")

3. 封装验证逻辑为函数(可选但更清晰)

为了代码更模块化,可以把单个数据包的验证逻辑封装成一个函数:

def process_passport(fields):
    # 第一步:检查必填字段是否齐全
    field_names = [item.split(':')[0] for item in fields]
    required_fields = {'byr', 'iyr', 'eyr', 'hgt', 'hcl', 'ecl', 'pid'}
    # 简化check_fields的实现,用集合运算更高效
    if not required_fields.issubset(field_names):
        return 0
    
    # 第二步:验证每个字段的取值
    for field_line in fields:
        field_name, _ = field_line.split(':', 1)
        # 跳过cid字段
        if field_name == 'cid':
            continue
        # 通过映射字典获取验证函数并执行
        validator = field_validators[field_name]
        if not validator(field_line):
            return 0
    return 1

额外优化建议

  • 简化check_fields:用集合的issubset方法比循环判断更简洁高效,就像上面process_passport里的写法。
  • 优化check_hcl:用正则表达式可以简化字符验证逻辑,比如:
    import re
    def check_hcl(line):
        _, value = line.split(':')
        return re.fullmatch(r'#[0-9a-f]{6}', value) is not None
    
  • 健壮性提升:在check_hgt里可以先判断单位是否合法(比如是否是cm或in),避免出现KeyError。

内容的提问来源于stack exchange,提问作者viGor027

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 04:14:07