#!/usr/bin/env/python # -*- coding:utf-8 -*- import re from pprint import pprint from washutil import table_label_cleal, find_seq_num # 本文件包含以下函数 # con_ans_split:将传进来的单道题(含答案或解析)按题干、答案、解析 拆分 # ans_structure_total:针对答案部分解析结构化汇总 # ans_structure: 拆分答案,并根据已拆分好的题目item_res 补上答案和解析 # stem_ans_struc_combine: 题干结构化与答案结构化的合并 # manyans_oneline_split(item_str, one_type_num):对一行多个答案的情况进行拆分 # only_parse_split: 拆分出答案和解析,主要针对答案页中的每个题的答案进行拆分 # get_ans_from_parse: 从已知解析中 挑选 答案 # def ans_structure_step1(anss, item_type_classify, item_res): # """ # 针对答案部分解析结构化汇总 # anss : 整个答案部分 # :return: dd = {'parse': , 'key': } # """ # anss = [k for k in anss if k.strip()] # ans_label = [k for k, a in enumerate(anss) if re.match("【答案】", a.strip())] # parse_label = [k for k, a in enumerate(anss) if re.match("【解析】", a.strip())] # if len(ans_label) == 1 and len(parse_label) == 1: # ans1 = anss[ans_label[0] + 1: parse_label[0]] # parse1 = anss[parse_label[0]+1:] # res_ans, flag1 = ans_structure_step2(ans1, item_type_classify, item_res,'group_ans') # res_parse, flag2 = ans_structure_step2(parse1, item_type_classify, item_res, 'group_parse') # if flag1 == flag2 == 1: # for idx, item_r in enumerate(item_res): # if not res_ans[idx]['key']: # if not res_parse[idx]['key']: # item_res[idx]['key'] = "见解析" # else: # item_res[idx]['key'] = res_parse[idx]['key'] # else: # item_res[idx]['key'] = res_ans[idx]['key'] # # if not res_ans[idx]['parse']: # item_res[idx]['parse'] = res_parse[idx]['parse'] # else: # 解析中的parse肯定有 # item_res[idx]['parse'] = res_ans[idx]['parse']+"
【解析】"+res_parse[idx]['parse'] # return item_res # elif flag1 == 2: # return "【答案】组中题型数量与题目中不一致,请重点检查题目序号,重新手输题目序号" # elif flag2 == 2: # return "【解析】组中题型数量与题目中不一致,请重点检查题目序号,重新手输题目序号" # else: # return '【答案】组和【解析】组中题型数量与题目中均不一致,请重点检查题目序号,重新手输题目序号' # else: # res_ans, flag1 = ans_structure_step2(anss, item_type_classify, item_res) # if flag1 == 1: # for idx, item_r in enumerate(item_res): # item_res[idx]['key'] = res_ans[idx]['key'] # item_res[idx]['parse'] = res_ans[idx]['parse'] # else: # # return "答案中题目数量与题目中不一致,①请重点检查题目序号,重新手输题目序号;②将参考答案开头没用的信息去掉;" \ # # "③是否有遗漏答案或答案格式不对;④答案中若存在一行多个答案时,保证每个题的答案间要留有多个空格!" # return res_ans # return item_res # # # def ans_structure_step2(anss, item_type_classify, item_res, *group): # """ # 拆分答案,并根据已拆分好的题目item_res 补上答案和解析 # 有的答案放在表格里,如选择题、填空题、判断题,有的一行多个答案 # 思路:1.先按一行没有多个题答案的情况取答案,数量与题干不同 时 >>>> 2.再按一行多个答案的情况取答案: # 1)先判断表格,拿到表格的答案;2)一行多个答案 # anss: 一组按所有不重复题号的答案 # item_type_classify: 题目中对各题型的统计 # :return: [{'parse': , 'key': },{},{}] # """ # while not anss[0]: # anss = anss[1:] # if re.match(".+?省.+?试[卷题]|[^a-zA-Z]*?【专题】", anss[0]): # anss = anss[1:] # # # 预处理: 对答案部分的题号进行处理, 将(\d)类型的题号改为\d、类型 # sub_item_no = [int(no[0]+no[2]) for no in # re.findall(r'\n\s*([1-9]|[1-4][0-9])\s*[..、、]|\n\s*([1-9]|[1-4][0-9])\s*[..、、].+?\s+([1-9]|[1-4][0-9])\s*[..、、].+?', # "\n" + "\n".join(anss))] # if len(sub_item_no) <= 2: # sub_item_no = [int(no[0]+no[2]) for no in re.findall(r'\n\s*\(([1-9]|[1-4][0-9])\)\s*[..、、]?' # r'|\n\s*\(([1-9]|[1-4][0-9])\)\s*[..、、]?.+?\s+\(([1-9]|[1-4][0-9])\)\s*[..、、]?.+?', # "\n" + "\n".join(anss))] # if len(sub_item_no) > 3: # anss = re.sub(r'\n\s*\(([1-9]|[1-4][0-9])\)\s*[..、、]?', "\n" + r"【@\1、", "\n" + "\n".join(anss)) # anss = re.sub(r'(\n【@([1-9]|[1-4][0-9])、.+?\s+)\(([1-9]|[1-4][0-9])\)\s*[..、、]?', r"\1【@\3、", anss) # anss = anss.replace("【@", "").split("\n")[1:] # # # --------- 一行多个答案的情况----存在一行中有选择题和填空题答案,填空题答案尽量每题占一行---------- # all_item_ans = [] # table_ans = [] # ans_no = [] # while anss and "table" in anss[0]: # 答案以表格形式呈现, 表格应放在前两行位置,不要插在答案中间 # row_list = [] # 要求表格形式为 横纵分明 ,不存在合并 # for tt in re.finditer('(((?!()).)*)', anss[0], re.S): # 先划分每行 # tt_list = re.split(r'

|

|||', tt.group(1)) # 再划分每列 # # row_list.append([col for col in tt_list if col.strip()]) # 也有可能答案为空 # row_list.append(tt_list) # if row_list: # print("^^^^^^存在答案放在表格里的情况!^^^^^^^") # if len(row_list) % 2 != 0: # print('表格形式呈现的答案不是偶数行') # else: # # print("row_list:", row_list) # for k, v in enumerate(row_list): # # print('-----',v) # if (k + 1) % 2 == 1: # 奇数行==》答案序号行 # item_no = [int(i) if re.sub(r"[^\d]", "", i) else -1 for i in v] # item_no_st = [num for num, i in enumerate(item_no) if i != -1] # 可能开头是-1 # ans_no.extend([i for i in item_no if i != -1]) # 表格序号 # table_ans.extend(row_list[k + 1][item_no_st[0]: item_no_st[-1] + 1]) # 表格答案 # anss = anss[1:] # # 先按一行没有多个题答案的情况取答案 # anss_str = table_label_cleal("\n" + "\n".join(anss)) # if re.search(".+?
", anss_str) is None: # anss_str = anss_str.split("")[-1].replace("", "") # anss_str = re.sub(r"([A-H])\s*[..](\s*([1-4][0-9]|[1-9])\s*[..、、])", r"\1 \2", anss_str) # anss_str = re.sub(r"([;;])(\s*([1-4][0-9]|[1-9])\s*[.、、])", r"\1 \2", anss_str) # # rest_item_split = re.split(r'\n+\s*[1-4][0-9]\s*[..、、]|\n+\s*[1-9]\s*[..、、]', anss_str) # if not rest_item_split[0]: # rest_item_split = rest_item_split[1:] # all_item_ans.extend(table_ans) # all_item_ans.extend(rest_item_split) # print("表格答案:", table_ans) # pprint(all_item_ans) # # ------------先按没有一行多个答案的情况------------------- # if item_type_classify and len(all_item_ans) == sum(list(item_type_classify.values())): # res1 = [] # for num1, one_ans in enumerate(all_item_ans): # parse = only_parse_split(one_ans, item_res[num1]["type"], item_res[num1]['stem']) # res1.append(parse) # return res1, 1 # elif not item_type_classify and len(all_item_ans) == len(item_res): # res1 = [] # for num1, one_ans in enumerate(all_item_ans): # parse = only_parse_split(one_ans, item_res[num1]["type"], item_res[num1]['stem']) # res1.append(parse) # return res1, 1 # else: # 答案个数与题目不一致时,再按一行多个答案处理(题目个数正常,答案个数比题目少时) # print('-----存在一行多个答案的情况-----') # all_item_ans = [] # all_item_ans.extend(table_ans) # # 再按一行多个答案的情况取答案 # manyans_oneline_split = re.split(r'\n\s*[1-4][0-9]\s*[..、、]|\n\s*[1-9]\s*[..、、]' # r'|(? len(row_ans): # ans_no.extend(list(range(temp_no[0]-len(row_ans), temp_no[0]))) # ans_no.extend(temp_no) # else: # print("答案序号有问题!!") # ans_no.extend(['']*len(row_ans)) # ans_no.extend(temp_no) # # print("manyans_oneline_split:************") # # pprint(manyans_oneline_split) # print("ans_no:", ans_no) # all_item_ans.extend(manyans_oneline_split) # combine_res = stem_ans_struc_combine(item_type_classify, item_res, all_item_ans, ans_no, group) # # if not combine_res: # # return '答案数量与题干数量不一致,请检查题干和答案中的题号,是否有遗漏答案或答案格式不对;' \ # # '答案中若存在一行多个答案时,保证每个题的答案间要留有多个空格!', 2 # # return combine_res # def stem_ans_struc_combine(item_type_classify, item_res, all_item_ans, ans_no, group): # """ # 题干结构化与答案结构化的合并 # :return: # """ # print("item_type_classify:", item_type_classify) # print("题干中的题目数量:", len(item_res)) # print("答案中的题目数量:", len(all_item_ans)) # if item_type_classify and len(all_item_ans) == sum(list(item_type_classify.values())): # res1 = [] # for num1, one_ans in enumerate(all_item_ans): # parse = only_parse_split(one_ans, item_res[num1]["type"], item_res[num1]['stem']) # res1.append(parse) # return res1, 1 # elif not item_type_classify and len(all_item_ans) == len(item_res): # res1 = [] # for num1, one_ans in enumerate(all_item_ans): # parse = only_parse_split(one_ans, item_res[num1]["type"], item_res[num1]['stem']) # res1.append(parse) # return res1, 1 # else: # print('答案数量与题干数量不一致,请检查题干和答案中的题号,是否有遗漏答案或答案格式不对;', # '答案中若存在一行多个答案时,保证每个题的答案间要留有多个空格!', 2) # print("试题个数:", len(item_res)) # print("答案中的题号:", ans_no) # # ----------------------是否正确对上序号还需进一步验证!!!!!!!!!!------------------------------- # res1 = []; simp_res = [] # err_n = 0 # 与题目id没对上号的个数, 默认答案一般也是从前往后排序 # for k, one_item in enumerate(item_res): # 以题目为主 # search_range = ans_no # if k+3-err_n <= len(ans_no): # search_range = ans_no[k-err_n:k+3-err_n] # elif k-err_n < len(ans_no): # search_range = ans_no[k-err_n:] # # print("答案的搜索范围search_range:",search_range) # if one_item['item_id'] in search_range: # 在对应位置前 # ans_no_st = [k1+k-err_n for k1, v1 in enumerate(search_range) if v1 == one_item['item_id']] # 默认取第一个作为对应答案 # # print("答案的位置{0}:{1}, ----对应题目id:{2}".format(ans_no_st, all_item_ans[ans_no_st[0]],one_item['item_id'])) # parse = only_parse_split(all_item_ans[ans_no_st[0]], one_item["type"], one_item['stem']) # one_item['key'] = parse['key'] # one_item['parse'] = parse['parse'] # res1.append(one_item) # if group == 'group_ans': # simp_res.append({'parse': "", 'key': parse['key'],'item_id':one_item['item_id']}) # if group == 'group_parse': # simp_res.append({'parse': parse['parse'], 'key': parse['key'],'item_id':one_item['item_id']}) # else: # err_n += 1 # one_item.update({'parse': "", 'key': ""}) # res1.append(one_item) # if group: # simp_res.append({'parse': '', 'key': '', 'item_id': one_item['item_id']}) # if simp_res: # return simp_res, 1 # # return res1, 2 # def one2more_ans_split(item_list, item_type): # """ # 对一行多个答案的情况进行拆分 # :return: # """ # manyans_oneline_split = [] # while item_list and \ # len(re.findall(r"(^|\s+)[1-9][0-9]?\s*[..、、]\s*(【答案】|答案\s*[::]?)?\s*[A-D]", item_list[0])) > 1: # print('选择题存在一行多个答案的情况!!!') # 主要以选择题的为主 # # # 处理 1.xxx 2.xxx 3.xxx # ans_line1 = item_list[0] # if not item_type or item_type.replace("题", "") in ["单选", "多选", "选择", "不定选择"]: # ans_line1 = re.sub(r"[^A-D\d..、、()]", "", item_list[0]) # # if re.match(r"[1-9][0-9]?[..、、][A-D]", ans_line1): # 第一个答案为选择题的情况 # one_ans_split = re.split(r'^\s*[1-9][0-9]?\s*[..、、]|\s+[1-9][0-9]?\s*[..、、]', item_list[0]) # if not one_ans_split[0]: # one_ans_split = one_ans_split[1:] # manyans_oneline_split.extend(one_ans_split) # else: # 第一个答案为非选择题或没有序号的情况 # one_ans_split = re.split(r'^\s*[1-9][0-9]?\s*[..、、]|\s+[1-9][0-9]?\s*[..、、]', item_list[0]) # if not one_ans_split[0]: # one_ans_split = one_ans_split[1:] # if manyans_oneline_split and not manyans_oneline_split[-1]: # 序号和答案跨行的情况 # manyans_oneline_split[-1] = one_ans_split[0] # manyans_oneline_split.extend(one_ans_split[1:]) # else: # manyans_oneline_split.extend(one_ans_split) # item_list = item_list[1:] # # if item_list: # # ans_line1 = re.sub(r"[^A-D\d..、、]", "", item_list[0]) # # if manyans_oneline_split and not manyans_oneline_split[-1]: # print('答案要求:题目序号不在行首时不要与该题答案跨行') # # # 填空题答案也可能一行多个 # if item_type == '填空题': # 在题干题型明确时 # one_type_ans_split = re.split(r'\n\s*[1-9][0-9]?\s*[..、、]|(?\s*$', item_parse): # item_parse = re.sub('\n\s*\s*$', "", item_parse) # item_ans = "" # if item_type.replace("题", "") in ["单选", "多选", "选择", "不定选择"]: # ans = re.search(r'故选\s*[::]?\s*' # r'|故选\s*[::]?\s*([A-Z;;和与、、\s]+)', item_parse.replace("$", "")) # if ans: # item_ans = ans.group(1) if ans.group(1) is not None else ans.group(2) # item_ans = re.sub(r"[.;;.]\s*$", "", item_ans) # elif not ans: # item_ans = "见解析" # elif item_type: # ans0 = re.search(r'故选\s*[::]?\s*([A-Z;;和与、、\s]+)[..;;。]?$', item_parse) # 试验题中可能还有选择题 # ans01 = re.search(r'故选\s*[::]\s*', item_parse) # 选择题的题型可能前面分错 # ans1 = re.search(r'(故|因[而此]|所以)\s*[::]?\s*(答案分?别?[为是填]?|填)\s*[::]?\s*(((?!()[..]?\s*(\n|$)', item_parse, re.S) # ans22 = re.search(r'(故|因[而此]|所以)\s*[::]?\s*(答案分?别?[为是填]?|填)\s*[::]?\s*([^∴∵因所故即【】]+?)([..]\s*(\n|$)|$)', item_parse) # ans21 = re.search(r'综上所述\s*[::]\s*([^∴∵故因所即【】]+?)[..;;]\s*$', item_parse) # ans3 = re.search(r'(故|因[而此]|所以|∴)\s*[::]?.+?[为是填]\s*[::]?\s*([^∴∵故因所即【】]+?)([..;;,,]\s*$|[..]\s*\n)', item_parse) # ans31 = re.search(r'(故|因[而此]|所以|∴)\s*([^当为是填∴∵故因所即则【】]+?)[..;;]\s*$', item_parse) # ans32 = re.search(r'(故|因[而此]|所以)\s*[::]?[^当为是填∴∵故因所即【】]+?[为是填]\s*[::]?\s*()[..]?\s*(\n|$)', # item_parse, re.S) # ans4 = re.search(r'\n\s*[==]([^=\n]+?)[..]?\s*$', item_parse) # ans42 = re.search(r'[==](?!")(((?!([故=∴即]|原式|因[而此]|所以|\n|=[^"])).)+?)[..]?\s*$', item_parse) # ans41 = re.search(r'原式\s*[==].+?[==](?!")(((?!(=|=[^"])).)+?|\s*)([..]?\s*$|[..]\s*\n)', item_parse) # if not (item_type == '填空题' and len(re.findall(r"_{2,}|_+([^_]*?)_+", res_con)) == 1) and \ # len(re.findall(r"[((]\d[))]|[\n::;;。】]([((](i{1,3}|[ⅰⅱⅲⅳⅠⅡⅢIV①②③④])[))]|[①②③④]\s*(?![+-]))", # item_parse.replace(" ", ""))) > 1 or "证明" in item_parse: # item_ans = "见解析" # elif ans0: # item_ans = ans0.group(1) # elif ans01: # item_ans = ans01.group(1) # elif ans1 or ans11: # item_ans = ans1.group(3) if ans1 else ans11.group(2) # elif ans2: # item_ans = ans2.group(3) # elif ans22: # item_ans = ans22.group(3) # elif ans21: # item_ans = ans21.group(1) # elif (ans3 or ans31 or ans32) and '证明' not in item_parse: # if ans3: # item_ans = ans3.group(2) # if ans31: # item_ans = ans31.group(2) # if ans32: # item_ans = ans32.group(2) # elif (ans4 or ans41 or ans42) and '证明' not in item_parse: # if ans4: # item_ans = ans4.group(1) # if ans41: # item_ans = ans41.group(1) # if ans42: # item_ans = ans42.group(1) # else: # item_ans = "见解析" # return item_ans # def con_ans_split(one_item_list, item_topic_name, topic_no): # """ # 将传进来的单道题(含答案或解析)按题干、答案、解析 拆分 # :param one_item_list: [str,str,str] 每个元素为一行数据, ocr一行行识别, 保留每行数据;如果是word,直接用wordbin拿到html格式进行解析 # :param item_topic_name:题型 # :param topic_no:题号 # :return: one_item:{"stem":xxxx,"key":xxx,"parse":xxx} # """ # pattern1 = re.compile(r"【(.*?)\s+(.*?)】|【(.*?)(.*?)】") # con0 = re.sub(r"】[::]", "】", "#&#".join(one_item_list)) # 是否换行后面再考虑 # con0 = re.sub(r"\[来源.*?\]", "", con0).replace("\xa0", " ").replace("\u3000", " ") # while re.search(pattern1, con0): # con0 = re.sub(pattern1, r"【\1\2】", con0) # 去掉 【】 中的图片和空格 # # big_struc_dict = {"type": item_topic_name, "topic_no": topic_no} # if re.search("【(答案|[解分][析答]|详解)】", con0): # label = re.findall("【(答案|[解分][析答]|详解|点[评睛])】", con0) # label_split = re.split(r"【答案】|【[解分][析答]】|【详解】|【点[评睛]】", con0) # big_struc_dict1 = dict(zip(label, label_split[1:])) # big_struc_dict1['con'] = label_split[0] # # 将键值为空的键删掉 # big_struc_dict.update({k: v for k, v in big_struc_dict1.items() if v.replace("#&#", "").strip() != ""}) # else: # big_struc_dict['con'] = con0 # # return big_struc_dict if __name__ == '__main__': # oneitem = {'stem': '7.化简÷的结果是(\u3000\u3000)\n' # 'A.B.C.D.\n'} # res = one_item_parse(oneitem, '单选题') # oneitem = ["1.下列说法正确的是(  )","A.射线是高速运动的电子流","B.氢原子可通过吸收光子实现从低能级向高能级跃迁", # "C.太阳辐射能量的主要来源是太阳内部发生的重核裂变","D.的半衰期是3.8天,1克经过7.6天后全部发生衰变", # "【答案】B","【解析】","【分析】","【详解】","A.γ射线是电磁波,故A错误;","B.按照波尔理论,氢原子吸收光子后,将从低能级向高能级跃迁,故B正确;", # "C.太阳辐射能量的主要来源是太阳中发生的轻核聚变,故C错误;","D.的半衰期是3.8天,7.6天是2个半衰期,根据可知,有发生衰", # "变,还剩下克没有衰变,故D错误。","故选B。"] # num = 1 # item_type = '选择题' # res = con_ans_split(oneitem, item_type, num) # pprint(res) one_ans = '故答案为:3.\n' parse = only_parse_split(one_ans, "填空题") print(parse) # a = dict(zip(["2","2","3"], [2,4,6])) # print(a) con = '【分析】 首先根据分式值为零的条件,可得;然后根据因式分解法解一元二次方程的步骤,求出x的值为多少即可.\n【解答】 解:∵分式的值为0,\n

\n

解得x=3,\n

即x的值为3.\n

故答案为:3.\n【点评】 (1)此题主要考查了分式值为零的条件' con = re.search(r'(故|因[而此]|所以)\s*[::]?\s*(答案分?别?[为是填]?|填)\s*[::]?\s*(((?!(