Python彩票号码校验脚本为何未移除含'week x'的错误条目?
我写了一段Python脚本,用来读取文件里的彩票号码行并校验错误。测试数据如下:
week 1;17,19,35,23,8,20,36 week 2;24,28,35,8,3,22 week x;23,29,38,1,35,18,25 week 4;21,2,22,14,4,28,38 week 5;5,37,20,15,3,14,9 week 6;6,29,7,14,16,18,1 week 7;24,31,14,23,4,3,29 week 8;32,21,26,1,15aa,14,17 week 9;8,13,25,12,33,34,35 week 10;29,27,30,13,7,38,26 week 11;34,3,7,24,16,20,38 week 12;15,28,2,29,16,10,8 week 13;32,22,13,14,21,28,26 week 14;37,4,20,3,1,33,10 week 1a5;17,8,38,18,9,32,25
其中第3周(week x)和第15周(week 1a5)因为周数格式错误应该被移除。我用整数校验逻辑处理,但脚本只移除了第15周的条目,没移除第3周的。我加了print True语句,但没触发输出——按说整数校验对'x'和'1a5'都应该抛出错误才对。我想排查这个逻辑的问题,同时弄清楚脚本为啥还遗漏了其他错误。我的脚本代码如下:
def filter_incorrect(): with open("lottery_numbers.csv") as sourcefile: entries = [] for line in sourcefile: line = line.replace("\n","") line = line.replace(";",",") parts = line.split(",") entries.append(parts) for result in entries: try: int(result[0].lstrip("week ")) == result[0].lstrip("week ") print(result[0] + " True") pass except: entries.remove(result) print (len(entries)) try: for i in range(1,len(result)): int(result[i]) == result[i] pass except: entries.remove(result) if len(result) != 8: entries.remove(result) try: for i in range(1,len(result)): if int(result[i]) > 39 or int(result[i]) < 1: entries.remove(result) except: pass for i in range(1,len(result)): for j in range(1,len(result)): if result[j] == result[i] and i != j: entries.remove(result) print(len(entries)) with open("correct_numbers.csv","w") as resultsfile: for entry in entries: resultsfile.write(f"{entry[0]};{entry[1]},{entry[2]},{entry[3]},{entry[4]},{entry[5]},{entry[6]},{entry[7]}\n")
问题根源分析
1. 遍历列表时直接修改导致元素跳过
这是最关键的问题:你在for result in entries循环里直接调用entries.remove(result),修改了原列表的长度和元素位置。Python的列表迭代器是按索引顺序遍历的,当你删除当前迭代的元素后,列表后续元素会向前移位,迭代器的下一次循环会跳过移位后的下一个元素。比如处理week x时把它移除,原本的第4个元素会变成新的第3个,但迭代器已经走到第4个索引,直接跳过了这个位置的元素,导致week x的后续校验逻辑没执行完全,甚至可能根本没触发移除操作。
2. 周数校验逻辑无效
你写的int(result[0].lstrip("week ")) == result[0].lstrip("week ")完全是多余的:整数和字符串永远不可能相等,这条语句只会返回False,但不会抛出异常——只有当int()转换失败时才会进入except块。不过即使转换失败,因为遍历修改列表的问题,也可能导致元素没被正确移除。
3. 其他校验逻辑的缺陷
- 号码格式校验:发现无效号码时直接移除元素,同样受遍历修改列表的影响,可能导致错误未被处理。
- 长度校验:如果元素已经被移除,再判断
len(result)会导致逻辑混乱,因为result还是原元素的引用,但列表里已经没有它了。 - 重复号码校验:嵌套循环里多次触发
entries.remove(result),可能导致同一元素被多次移除,引发异常;而且一旦发现重复就移除,没有提前终止循环,浪费资源。
修复后的脚本
解决核心思路:不修改原列表,而是创建新列表存储有效条目,同时重构校验逻辑,让每个校验步骤清晰独立:
def filter_incorrect(): valid_entries = [] with open("lottery_numbers.csv") as sourcefile: for line in sourcefile: line = line.strip() # 替代replace("\n",""),同时去除首尾空格 if not line: continue # 跳过空行,避免不必要的错误 # 拆分周数和号码部分,用split(";",1)确保只拆分一次,避免号码里有分号的情况 try: week_part, numbers_part = line.split(";", 1) except ValueError: print(f"移除格式错误的条目(无分号分隔): {line}") continue # 校验周数格式:必须是"week + 整数"的形式 try: week_num_str = week_part.lstrip("week ").strip() int(week_num_str) except ValueError: print(f"移除周数格式错误的条目: {line}") continue # 拆分号码列表 numbers = numbers_part.split(",") # 校验号码数量是否为7个 if len(numbers) != 7: print(f"移除号码数量错误的条目: {line}") continue # 校验每个号码的合法性:整数、1-39范围、无重复 valid_numbers = [] seen_numbers = set() has_error = False for num_str in numbers: num_str = num_str.strip() # 校验是否为整数 try: num = int(num_str) except ValueError: print(f"移除号码格式错误的条目: {line}") has_error = True break # 校验范围 if num < 1 or num > 39: print(f"移除号码超出范围的条目: {line}") has_error = True break # 校验重复 if num in seen_numbers: print(f"移除存在重复号码的条目: {line}") has_error = True break seen_numbers.add(num) valid_numbers.append(num_str) if has_error: continue # 所有校验通过,加入有效列表 valid_entries.append((week_part, valid_numbers)) print(f"最终有效条目数量: {len(valid_entries)}") # 写入结果文件 with open("correct_numbers.csv", "w") as resultsfile: for week_part, numbers in valid_entries: resultsfile.write(f"{week_part};{','.join(numbers)}\n") # 调用函数执行 filter_incorrect()
修复点说明
- 避免遍历修改原列表:用
valid_entries收集符合条件的条目,彻底解决迭代器跳过元素的问题。 - 周数校验优化:先拆分周数和号码部分,避免把分号换成逗号导致的结构混乱;校验周数时先去除多余空格,确保"week x"这种带空格的错误也能被检测到。
- 号码校验逻辑重构:逐个校验号码的格式、范围、重复,一旦发现错误就标记并跳过当前条目,逻辑清晰且高效。
- 增加错误提示:每个校验步骤都添加了具体的错误信息,方便排查问题。
- 空行处理:自动跳过空行,避免不必要的错误。
内容的提问来源于stack exchange,提问作者Dominic

