1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024 |
- #!/usr/bin/env/python
- # -*- coding:utf-8 -*-
- # 本文件包含以下函数
- # table_label_cleal:去掉表格中的换行符
- # html_cleal :html文件清洗
- # wash_after: 处理最终结果多余的换行符
- import re
- import shutil
- # from operator import itemgetter
- # from itertools import groupby
- # from PIL import Image
- import base64, os, random
- import time
- import hashlib
- from pprint import pprint
- # from bs4 import BeautifulSoup
- # UPLOAD_FOLDER = config.UPLOAD_FOLDER
- import configs
- from structure.stems_to_groups import parse_split2group, suojin
- from utils.equation_extract import get_equation_instr, get_simpstr2eqn
- from utils.field_eq2latex import get_latex
- from utils.html_again_parse import css_label_wash
- from structure import stems_to_groups
- def table_label_cleal(con):
- """
- 去掉表格中的【换行符】
- """
- # print(con)
- # print('------------------------------------------')
- con = re.sub(r"\n(\n|\t)+", "\n", con)
- count = 1
- while re.search(r"</?[a-z]+>\n(</?[a-z]+>|<td\s+\n*[a-z=\"\d]+>)", con, re.S) and count <= 10:
- con = re.sub("(</?t[dr]>|</?table>|</?tbody>|</?div>)\n(</?t[dr]>|</div>|</?table>|</?tbody>|<p>)",
- r"\1\2", con, flags=re.S)
- con = re.sub(r'(</?t[rd]>)\n(<td\s.+?>)', r'\1\2', con, flags=re.S)
- count += 1
- # if re.search(r"<table>(.|\n)+?</table>", con, re.S|re.M):
- # aa = re.search(r"(<table>(.|\n)+?</table>)", con, re.S|re.M)
- # con = con.replace(aa.group(1),aa.group(1).replace("\n",""))
- # 将空表格的情况去掉
- con = re.sub(r'<table>[\s\n\t]*?<tbody>[\s\n\t]*?(<tr>[\s\n\t]*?<td[^<>]*?>[\s\n\t]*?<p>[\s\n\t]*?</p>'
- r'[\s\n\t]*?</td>[\s\n\t]*?</tr>[\s\n\t]*?)+</tbody>[\s\n\t]*?</table>[\s\n\t]*?<p>', "", con,
- flags=re.S)
- con = re.sub(r'(</table><p>)\s*([((]\s*\d\s*[))])', r'\1\n\2', con)
- return con
- def base642img(html_data, wordid):
- """
- 【基于mathjax渲染输出是css-html格式】
- 将base64编码的图片保存到本地
- :return:
- """
- # 二进制图片进行转化, 按“word_id”建立文件夹
- # time_str = datetime.datetime.strftime(datetime.datetime.now(), '%Y_%m_%d')
- # file_path = configs.IMG_FOLDER + '/' + str(self.wordid)
- # if not os.path.exists(file_path):
- # os.makedirs(file_path)
- # else:
- # 思路1:删除图片,重建文件夹,【所有的新图片都是以base64格式传过来的】
- # shutil.rmtree(file_path)
- # os.makedirs(file_path)
- # 思路2:每一次再解析都将base64图片保存到本地再以路径形式返回
- # st = len(os.listdir(file_path)) # 不要以序号索引的形式命名
- # 统计所有base64编码
- all_base64_image = re.findall(r'(<img ([a-z]+="[^"]*?" )?src="(data:image[^>"]+?)"(.*?)\s*/?>)', str(html_data), flags=re.S)
- if all_base64_image:
- file_path = configs.IMG_FOLDER + '/' + str(wordid)
- if not os.path.exists(file_path):
- os.makedirs(file_path)
- # 新图片命名1、时间戳+随机数;2、md5值命名
- # name_list = random.sample(range(100000, 999999), len(all_base64_image))
- for n, img in enumerate(all_base64_image):
- img1 = img[2].split(",", maxsplit=1)
- img_type_info = re.search("data:image/(.+?);base64", img1[0])
- img_type = img_type_info.group(1) if img_type_info else "" # 图片格式
- # 可能还有alt和style的属性,暂时先不要
- w_info = re.search('( width="\d+")', img[3])
- h_info = re.search('( height="\d+")', img[3])
- img_data = base64.b64decode(str(img1[-1]))
- if img_type:
- # save_path = os.path.join(configs.new_img_ip, get_md5(n)+"."+img_tape)
- pmd5 = hashlib.md5(img_data)
- # img_name = "new_image" + str(int(time.time())) + str(name_list[n]) + "." + img_type # 时间戳+随机数
- img_name = "new_image" + pmd5.hexdigest() + "." + img_type
- save_path = os.path.join(file_path, img_name)
- with open(save_path, 'wb') as f:
- f.write(img_data)
- flag_behind = '" />'
- if w_info and h_info:
- flag_behind = '"' + w_info.group(1) + h_info.group(1) + ' />'
- temp_img = '<img src="' + configs.new_img_ip + '/' + str(wordid) + '/' + img_name + flag_behind
- html_data = html_data.replace(img[0], temp_img)
- return html_data
- class HtmlWash:
- """
- html文本清洗
- 批量再解析中,新增图片信息替换的文本返回作为ocr保存文本,
- 继续往下清洗的文本,则进入结构化解析逻辑中
- """
- def __init__(self, html, wordid, subject, is_reparse=0):
- """
- html文本清洗
- 批量再解析中,新增图片信息替换的文本返回作为ocr保存文本,
- 继续往下清洗的文本,则进入结构化解析逻辑中
- """
- # super().__init__(html, wordid, is_reparse, must_latex)
- self.html = html
- self.wordid = wordid
- self.is_reparse = is_reparse
- self.subject = subject
- self.sub_list = ["</?div>", "</?b>", "</?caption>", "</?center>", "</?cite>", "</?code>", "</?colgroup>",
- "</?menu>", "</?dd>", "</?dir>", "</?li>", "</?article>", "</?header>", "</?ruby>",
- "</?summary>", "</?details>", "</?strike>", "</?small>", "</?select>",
- "</?section>", "</?script>", "</?[su]>", "</?var>", "</?ul>", "</?tt>", "</?title>",
- "</?thead>",
- "</?tfoot>", "<hr />", "<hr>", ""]
- self.sub_dd = {'×': '×',
- '÷': '÷',
- '°': '°',
- '·': '·',
- '±': '±',
- 'º': 'º',
- '¹': '¹',
- '²': '²',
- '³': '³',
- '½': '1/2',
- '¼': '¼',
- '¾': '¾',
- '¥': '¥',
- 'm³': 'm³',
- # '<': '<',
- '£': '£',
- # '∠<': '<',
- '>': '>',
- "A": "A",
- "А": "A",
- "Α": "A",
- "B": "B",
- "В": "B",
- "в": "B",
- "Β": "B",
- "C": "C",
- "С": "C",
- "c": "c",
- "с": "c",
- "D": "D",
- "Ε": "E",
- "E": "E",
- "F": "F",
- "G": "G",
- "g": "g",
- "m": "m",
- "N": "N",
- "s": "s",
- "t": "t",
- "/": "/",
- "=": "=",
- "-": "-",
- "2": "2", "3": "3", "4": "4", "5": "5", "6": "6",
- "7": "7", "8": "8", "9": "9", "1": "1", "0": "0",
- ' ': ' ',
- ' ': ' ',
- "〖": '【',
- "〗": '】',
- "題": '题',
- "单项选择": '单选',
- "多项选择": '多选',
- "不定项选择": '选择',
- "双项选择": '多选',
- "实验与探究题": '实验',
- }
- def new_pic_sub(self):
- """
- 针对base64图片先保存到本地,入库时再换成腾讯云线上地址
- # 第一版:再解析中,将二进制图片进行转化,图片怎么保存比较好,先再“天数”建立文件夹
- 第一版:再解析中,根据“word_id”建立文件夹
- :return:
- """
- if self.is_reparse:
- # css 标签清洗
- self.html = css_label_wash(self.html)
- # print(self.html)
- # 保存base64编码的图片
- self.html = base642img(self.html, self.wordid)
- self.new_html = self.html
- def html_cleal(self):
- # =======清洗mathjax标签========
- if "MathJax" in self.html: # 再解析中存在mathjax公式渲染的标签
- all_mathjax = re.findall('(<span class="MathJax_Preview".*?</script>(</span>)*)', self.html)
- for jax in all_mathjax:
- latex = re.findall('<script .+?">(((?!(</)).)*?)</script>(</span>)*', jax[0])
- if latex:
- latex = "${}$".format(latex[0][0])
- self.html = self.html.replace(jax[0], latex)
- else:
- self.html = self.html.replace(jax[0], "")
- # ======再解析中的css清洗及新图片处理=====
- self.new_pic_sub()
- # =====特殊符号处理=====
- html2txt = re.sub(r"|".join(self.sub_list), "", str(self.html)) # ("", " ") #2020/4/7
- html2txt = re.sub("|".join(self.sub_dd.keys()), lambda x: self.sub_dd[x.group()], html2txt) # 2020/4/1,4/7,4/20
- html2txt = re.sub("[不非]定[向项]选择", "不定选择", html2txt)
- html2txt = html2txt.replace(r"\\[{\\text{V}}V\]", "Ⓥ").replace(r"\\[{\\text{A}}A\]", "Ⓐ") \
- .replace(r"\\[{\\text{W}}W\]", "Ⓦ").replace(r"\\[{\\text{X}}X\]", "Ⓧ").replace(r"\\[{\\text{G}}G\]", "Ⓖ") \
- .replace("\uf067", "γ").replace('', "γ").replace('\uf020', "").replace("\u3000", " ")\
- .replace("\u2003", " ").replace("\x7f", " ").replace("\xa0", "")
- html2txt = re.sub(r"(<p>\s*)【例题(\d+)】", r"\1\2、", html2txt)
- html2txt = re.sub(r"\\\(|\\\)", "$", html2txt)
- # 把格式标签单独拆分为一行,再在题目切分为小题完了之后再组起来!!!!!
- html2txt = re.sub(r'(<p style="text-(indent|align):.*?">)', r"\1</p><p>", html2txt)
- # 域公式的转化处理;<sub>\<sup>可以在前端显示,不需要用latex渲染
- try:
- html2txt, newhml = get_latex(html2txt, self.is_reparse, self.wordid)
- if newhml: # 存在域公式转图片时,需要将原文本的域公式也转为图片信息
- self.new_html = newhml
- html2txt = html2txt.replace("【omml-latex】", "")
- except:
- html2txt = html2txt.replace("【omml-latex】", "")
- # 字符串公式的处理:如Fe<sub>2</sub>O<sub>3</sub>, 在结构化之后处理比较好
- # <br/>处理
- html2txt = re.sub(r"<br\s*/?>", "\n", html2txt)
- # =====题型行的统一处理=====
- # ---->>>>>题型行可能放在表格中
- if len(re.findall("</table>", html2txt)) >= 8: # 这个限制还不太严谨
- for tt in re.finditer('<tr>(((?!(</?tr>)).)*)</tr>', html2txt, re.S):
- tt_list = re.split(r'^\s*<td[^<>]*?>|</p></td>|</td>[\n\s]*?<td[^<>]*?>'
- r'|</td>\s*\n|</td>\s*$|\n\s*<td[^<>]*?>|<td[^<>]*?><p>',
- tt.group(1).strip()) # </td>\s*[$\n]这样无效
- tt_list = [col for col in tt_list if col.strip()]
- if " ".join(tt_list).replace(" ", "") in ['得分评卷人', '评卷人得分']:
- html2txt = html2txt.replace(tt.group(0), "")
- else:
- pass
- # html2txt = html2txt.replace(tt.group(0), "<p>" + " ".join(tt_list) + "</p>")
- # html2txt = re.sub(r"</?tbody>|</?table>|</?div>", "", html2txt)
- # ---->>>>>end
- html2txt = re.sub(r"(</table>)\s*([一二三四五六七八九十]\s*[、..、::]?.{2,6}题)", r"\1</p>\2", html2txt)
- html2txt = re.sub(r'([一二三四五六七八九十])\s*[、..、,,::]\s*(论述|填空|探究)题?[与和、、,,\s]*?(计算题|实验题)', r"\1、\3", html2txt)
- html2txt = re.sub(r'<td[^<>]*?><p>(([一二三四五六七八九十])\s*[、..、,,::]\s*(.{2,4}题)\s*</p>)</td>[^p]*?<p>', r"\1",
- str(html2txt), flags=re.S)
- html2txt = re.sub(r'<td[^<>]*?>\s*(([一二三四五六七八九十])\s*[、..、,,::]\s*(.{2,4}题)\s*)</td>[\n\s]*?</tr>', r"\1",
- str(html2txt), flags=re.S)
- html2txt = re.sub(r"<p>\s*([一二三四五六七八九十])\s*[、..、,,::]?\s*(计算|[解简]答|实验|作图)题?[与和、、,,\s]*?(计算|[解简]答|实验|作图)",
- r"<p>\1、\2题", html2txt)
- html2txt = re.sub(r'<p>\s*[((]\s*[一二三四五六]\s*[))]\s*必考题\s*(.?|.+?分\s*[.。.]?)\s*</p>', "", html2txt)
- html2txt = re.sub(r'<p>\s*[((]\s*[一二三四五六]\s*[))]\s*选考题\s*.?\s*.{,4}(?<!\d)(\d+分)\s*[,,。].{,50}</p>',
- r"<p>【选做题】:'\1'</p>", html2txt)
- html2txt = re.sub(r'<p>\s*[((]\s*[一二三四五六]\s*[))]\s*选考题\s*(.?|.+?分\s*[.。.]?)\s*</p>', "<p>【选做题】</p>", html2txt)
- html2txt = re.sub(r'<p>\s*([一二三四五六七八九十])\s*[、..、,,::]?\s*(单项?选择?|非?选择|多项?选择?|不定选择|填空|计算|[解简]答|实验|作图)题?\s*</p>',
- r"<p>\1、\2题</p>", html2txt)
- html2txt = re.sub(r'([一二三四五六七八九十])\s*[、..、,,::]?\s*(单选|单项选择|选择|不定选择|多选|多项选择|填空|计算|[解简]答|实验|作图)\s*(?!题)'
- r'([((]\s*本题|.*?\d分)', r"\1" + "、" + r'\2' + "题" + r"\3", html2txt)
- html2txt = re.sub(r'([一二三四五六])\s*[、..、,,::]?\s*(单选|单项选择|非?选择|不定选择|多选|多项选择|填空|计算|[解简]答|实验|作图)题',
- r"\1" + "、" + r'\2' + "题", html2txt)
- html2txt = re.sub(r'([一二三四五六七八九十])\s*[、..、,,::]?\s*[((]\s*本大题(.*?选项中)', r"\1" + "、" + "选择题", html2txt) # + r"\2"
- html2txt = re.sub(r'<p>\s*([一二三四五六七八九十])\s*[、..、,,]?\s*[((本大题]*?(.*?选项中)', r"\1" + "、" + "选择题", html2txt)
- if self.subject != "语文":
- html2txt = re.sub(r'([一二三四五六七八九十])\s*[、..、,,::]?\s*([((]\s*(每小题|本大?题)((?!(选项)).)+?[))]|综合题)',
- r"\1" + "、" + "解答题", html2txt)
- else:
- html2txt = re.sub(r'([一二三四五六七八九十])\s*[、..、,,::]?\s*([((]\s*(每小题|本大?题)((?!(选项)).)+?[))]|综合题)',
- r"\1" + "、" + "综合题", html2txt)
- html2txt = re.sub(r'(?<!<p>)\s*([一二三四五六七八九十]\s*[、..、,,::]?\s*(单项?选择?|选择|不定选择|多项?选择?|填空|计算|[解简]答|实验|作图)题)',
- r'</p>\n<p>\1', html2txt)
- # html2txt = re.sub(r'<p>\s*第[Ⅰ1I]卷\s*</p>\n?<p>\s*本卷共\d{1,2}个?小?题.*?四个选项.*?\n?<p>\s*(\d\s*[、..、])'
- # r'|<p>第[Ⅰ1I]卷\s*[((]选择题[))]</p>\n?<p>本卷共\d{1,2}个?小?题.*?\n?<p>\s*(\d\s*[、..、])',
- # r"<p>一、选择题</p>\n<p>\1\2", html2txt)
- # html2txt = re.sub(r'<p>\s*[^一二三四五六七八九十]{,3}\s*[、..、]\s*(选择|不定选择|单选|多选|计算|[解简]答|实验|作图)题', r"<p>一、\1题", html2txt)
- # =====答案解析关键字的统一处理=====
- html2txt = re.sub(r'【\s*(<img src=((?!/>).)+?/>\s*)*?([解答])\s*(<img src=((?!/>).)+?/>\s*)*?([析案])\s*'
- r'(<img src=((?!/>).)+?/>\s*)*?】', r"【\3\6】", str(html2txt)) # 2022/4/28
- html2txt = re.sub(r'<p>\s*(解\s*[::])', r"<p>【解答】", str(html2txt))
- html2txt = re.sub(r'(<p>|<br\s*/>|\n)\s*(参考译文\s*[::])', r"\1【参考译文】", str(html2txt))
- html2txt = re.sub(r'【[^【】]*?(答案|[解分][析答]|详解|点[评睛])[^【】]*?】', r"【\1】", str(html2txt))
- html2txt = re.sub(r'(\n\s*|\s{2,})(答案|解析|解答|详解|点评|点睛|考点|专题)\s*[::]', r"\1【\2】", str(html2txt))
- html2txt = re.sub(r'(\n|^|<p>)\s*(([1-9]|[1-4][0-9])\s*[..、、])?\s*\[\s*(答案|解析|解答|详解|点评|点睛|考点|专题)\s*\]',
- r"\1\2【\4】", str(html2txt))
- html2txt = re.sub(r'(\n|^)\s*(分析)\s*[::]', r"【\2】", str(html2txt))
- if "【解析】" not in html2txt and "【解答】" in html2txt and "【分析】" not in html2txt:
- html2txt = re.sub(r'【解答】', "【解析】", str(html2txt))
- # =====其他关键字的处理=====
- html2txt = re.sub(r'<p>\s*(类型|知识点|考查角度|拔尖角度)[一二三四五六七八九十\d+][^p]*?</p>', "", str(html2txt))
- html2txt = re.sub(r'<p>\s*(选修[\d-]*?[::].{2,15})\s*</p>', r"<p>【章节】\1</p>", html2txt)
- html2txt = re.sub(r'<p>\s*([一二三四五六]\s*[、..、]?)?\s*(\[.{2}-*?选修[\d-]*?.*?\])\s*([((]\d+分[))])?\s*</p>',
- r"<p>【章节】\2</p>", html2txt)
- html2txt = re.sub(r'<p>\s*(基础|中档|综合)题[^p题]*?</p>|<p>\s*【(考点|专题)】[^p]*?</p>', "", str(html2txt))
- html2txt = re.sub(r'<p>\s*(基础训练|提升训练|探究培优)</p>', "", str(html2txt))
- html2txt = re.sub(r'<p>注意事项[::]\s*</p>(\n+\s*<p>\s*\d\s*[、..、][^/]+?</p>)+', "", html2txt, flags=re.S)
- html2txt = re.sub(r'<p>注意事项[::]\s*\d\s*[、..、][^/]+?</p>(\n+\s*<p>\s*\d\s*[、..、][^/]+?</p>)+', "", html2txt,
- flags=re.S)
- html2txt = re.sub(r'[((]\s*([A-Z\dⅠⅡⅢⅣⅤ]+|IV)\s*[))]', r"(\1)".replace(" ", "").replace("(IV)", "Ⅳ"), html2txt)
- html2txt = re.sub(r'[((](\s*\d\s*\d?\s*分?\s*)[))]', "(" + r'\1'.replace(" ", "") + ")", html2txt)
- html2txt = re.sub(r'\[来源:.*?\]', "", html2txt)
- html2txt = re.sub('<p>欢迎访问.*?</p>', '', html2txt)
- html2txt = re.sub('w\s*w\s*w\..*?(\.\s*c\s*o\s*m|\.cn)+|(?<!["“=])http:.*?\.(com|cn|org)', "",
- html2txt) # ww w.gkstk.com
- # html2txt = re.sub(r'<(table|td|tr) ([a-z]+="\d+")>', r'<\1>', html2txt)
- html2txt = re.sub(r'<table ([a-z]+="\d+")>', r'<table>', html2txt)
- html2txt = re.sub(r'<p>\s*第\s*[二三四ⅡⅢⅣ]\s*(卷|部分)\s*([((].*?[))]|非?选择题.{,8})?\s*</p>', "<p>【非选择题】</p>", html2txt)
- # == == =对可能的题型行的处理 == ==
- html2txt = re.sub("<p>【非选择题】</p>((\s|\n|<p>|</p>)*\d{1,2}\s*[..、、].+?)", r"<p>二、解答题</p>\1", html2txt)\
- .replace("【非选择题】", "")
- # =====选项的处理=====
- html2txt = re.sub(r'(<p>\s*([1-9]|[1-9][0-9])\s*[..、、].+?[((]\s*[))])\s*(A\s*[..、、][^/]*?</p>)',
- r"\1</p>\n<p>\3", str(html2txt))
- # =====题号的处理=====
- html2txt = re.sub(r'([ED]\s*[、..、].*?(\s|</su[pb]>\s*))(([1-9]|[1-9][0-9])\s*[、..、])',
- r"\1</p>\n<p>\3", html2txt)
- html2txt = re.sub(r'((</?p>|\n)\s*(<img src=.*?"\s*/?>\s*)?([1-9]|[1-9][0-9]))\s*'
- r'([((]\s*(\d{1,2}[.\s\d]*?分|.{2,3}题?)\s*[))]|解析?\s*[::]|【解析】)', r"</p>\1、\5", html2txt)
- html2txt = re.sub(r"<p>\s*([1-9]|[1-9][0-9])\s*([((]20\d{2}\s*[\u4e00-\u9fa5、、]{2,9}[))])", r"<p>\1、\2",
- html2txt)
- html2txt = re.sub(r"<p>\s*([1-9]|[1-9][0-9])\s*(【(解析?|答案?)】|(解析?|答案?)\s*[::]|\[(答案|解析)\])", r"<p>\1、\2",
- html2txt)
- html2txt = re.sub(r"<p>\s*([1-9]|[1-9][0-9])\s*([((]\s*\d+\s*分?\s*[))])?(【(解析?|答案?)】|(解析?|答案?)\s*[::]"
- r"|\[(答案|解析)\])", r"<p>\1、\2\3", html2txt)
- html2txt = re.sub(r"(</?p>|\n)\s*(<img src=((?!/>).)+?/>)\s*([1-9]|[1-9][0-9])\s*"
- r"([((]20\d{2}\s*[\u4e00-\u9fa5、、]{2,9}[))])", r"<p>\2</p>" + "\n" + r"<p>\4、\5", html2txt) # 【susp_img】
- html2txt = re.sub(r'(</?p>|\n)((\s*<su[bp]>\s*)?<img src=.*? height="[\d.]+p[tx]"\s*/?>(\s*</su[bp]>)?\s*)'
- r'(([1-9]|[1-9][0-9])\s*[、..、])', r"</p>\2</p>" + "\n" + r"\5", html2txt)
- html2txt = re.sub(r"(<p>((?!<p>).)+?(\s|[/\"]>))(([1-9]|[1-9][0-9])\s*[、..、].{,20}本[大小]?题\d+分)",
- r"\1</p>" + "\n<p>" + r"\4", html2txt)
- html2txt = re.sub(r"</?p>((\s*<su[bp]>\s*)?<img src=.*?/>(\s*</su[bp]>)?((\s*<su[bp]>\s*)?"
- r"<img src=((?!/>).)+?/>(\s*</su[bp]>)?)*?\s*)\s*(([1-9]|[1-9][0-9])\s*[、..、])",
- r"</p>\1</p>" + "\n<p>" + r"\8", html2txt, flags=re.S)
- html2txt = re.sub(r'(<p>\s*[一二三四五六七八九十].*?题\s*\(.+?分.*?\))\s*(([1-9]|[1-9][0-9])\s*[、..、].*?)</p>',
- r"\1</p>\n<p>\2</p>", html2txt)
- html2txt = re.sub(r'(<p>\s*[一二三四五六七八九十].*?题\s*\(.+?分.*?\))\s*(([1-9]|[1-9][0-9])\s*[、..、].*?)</p>',
- r"\1</p>\n<p>\2</p>", html2txt)
- html2txt = re.sub(r'(<p>.*?[..]{6,}\s*\d+分)\s*(([1-9]|[1-9][0-9])\s*[、..、].*?)</p>', r"\1</p>\n<p>\2</p>", html2txt)
- html2txt = re.sub(r'([1-9]|[1-9][0-9])\s*([((]\s*\d{1,2}[.\s\d]*?分\s*[))])\s*[、..、]', r"\1" + "、" + r"\2", html2txt)
- # =====图片的处理=====
- # 1>>根据图片宽高的异常值判断删除隐藏图片
- def sub1(ss):
- if float(ss.group(1)) <= 3 and float(ss.group(2)) <= 3:
- return ""
- else:
- return ss.group(0)
- html2txt = re.sub(r'<img src=.*? width="([\d.]+)p[xt]" height="([\d.]+)p[xt]"\s*/?>', sub1, html2txt)
- # 2>>将图片中带有的汉字去掉
- html2txt = re.sub(r'(<img src=.*?) alt=".+?"', r"\1", html2txt)
- html2txt = re.sub(r'(<img src=(?!\sstyle=)+?(?<!\\)\")>', r"\1 />", html2txt) # 将">换为" />
- # 3>>建立图片id字典,对原图片信息第一次替换
- html2txt = re.sub(r'( src=".*?files)\\image', r"\1/image", html2txt)
- all_image = re.findall(r'<img src=".*?image[\da-z]+\..*?[/\"]>', html2txt)
- src2subs = {}
- subs2src = {}
- for src in all_image:
- # 校本题库上传的图片名称是随机数,故设置映射
- # kk = re.search('(<img src=".*?image\d+\.(png|gif|jpg|jpeg))', src)
- # new_src = src.replace(kk.group(1), self.img_url[kk.group(1)]) if type(self.img_url) == dict and kk else src
- # 图片信息简化替换
- new_src = re.sub(r'( data-latex)="\s*\\\[(.*?)\\\]\s*"', r'\1="$\2$"', src)
- new_src = re.sub(r'( data-latex="\$[^"]+?\$")',
- lambda x: x.group(1).replace("<", " \lt ").replace(" ", " "), new_src)
- latex_info = re.search(r'<img src=".*?/(new_)?image([\da-z]+)\..*?(data-latex=".*?")', src)
- mathpix = " " + latex_info.group(3).replace("\n", "").strip().replace(" ", " ") if latex_info else ""
- if mathpix and len(mathpix) > 20:
- mathpix = ""
- w_h_info = re.search(r'<img src=".*?/(new_)?image([\da-z]+)\..*?width="([\d.]+)[pxt]*?"\s*height="([\d.]+)[pxt]*?"', src)
- w_h = " w_h=" + w_h_info.group(3).split('.')[0] + "*" + w_h_info.group(4).split('.')[0] \
- if w_h_info and not mathpix else "" # w_h 和 mathpix只存在一个
- image_id = re.search(r'<img src=".*?/(new_)?image([\da-z]+)\.', src).group(2)
- src2subs[src] = '<imgsrc' + image_id + w_h + mathpix + "/>"
- subs2src['<imgsrc' + image_id + w_h + mathpix + "/>"] = new_src
- for k, v in src2subs.items():
- html2txt = html2txt.replace(k, v)
- # ------------------------------------------------------------------------
- # ========html 转 list=========
- html2txt = re.sub(r'(</?div>|</table>|</?body>)(\n\s*)*?<p>', r"\1</p>" + "\n<p>", html2txt, flags=re.S)
- # >>>>>> <table>先替换后再切割
- # 不能简单按 \n 切割,表格里面也可能有换行,应该先替换后再切割
- subs2table = {}
- all_table = re.findall(r'<table>.*?</table>', html2txt, flags=re.S)
- for k, v in enumerate(all_table):
- subs2table["<t{}b>".format(str(k))] = v
- html2txt = html2txt.replace(v, "<t{}b>".format(k))
- # <造成的css标签冲突处理 2021-10-13
- def sub2(ss):
- if re.search(r'^(img|/?h[123456]|/?su[bp]>|t\d+b>|br\s*/?>'
- r'|/?(p|span|font|article|ul|ol|div|strong|em|table|t?body|html|head|t[drh])(\s*|\s+style=.*?")>'
- r'|/?[a-z]+ (style|rowspan|colspan|class)=.*?">)', ss.group(1)) is None:
- r1 = "<{}".format(ss.group(1))
- r1 = re.sub(r"<(span (class|style)=)", r"<\1", r1)
- r1 = re.sub(r"<(p (class|style)=)", r"<\1", r1)
- return r1
- else:
- return "<{}".format(ss.group(1)).replace("</body>", "").replace("</html>", "")
- html2txt = re.sub("<([^<]{1,30})", sub2, html2txt)
- # >>>>>> html 切割
- con_list = sum([re.split('<p>|<h[12345]>', i) if len(re.findall("<p>|<h[12345]>", i)) > 1
- else [i] for i in re.split(r"\n+|</p>(?!</td>)|</h[12345]>", html2txt)], []) # html2txt)[:-1]
- con_list = [re.sub(r"^\n*\s*(<p>|<h[12345]>)+", "", ii) for ii in con_list]
- # pprint(con_list)
- # >>>>>> <table> 替换回去
- if subs2table:
- con_list = [re.sub(r"|".join(subs2table.keys()), lambda x: subs2table[x.group()], ii) for ii in con_list]
- # 剩余个别标签处理
- con_list = [re.sub(r"^<([a-z]+)>[\s\t\n]*</\1>$", "", i.strip()) for i in con_list] # 2020/4/7,14
- con_list = [re.sub(r"^(<table>|</td>|<td[^<>]*?>|</?tr>)+?(.|\n)+?([一二三四五六七八九十])\s*[、..、]\s*(.{2,4}题)(.|\n)+?</table>",
- r"\3、\4", i.strip())
- for i in con_list]
- # 把最后可能还存在的</?p>或考号信息去掉
- con_list = [re.sub("</?p>|[…O•.\s]*?密[…O•.\s]*?封[….O•\s]*?装?[…O•.\s]*?订?[….O•\s]*?线?[….O•\s]*?$"
- "|((学校|班级|姓名|座位号|准考号|[学考]号)[\s::_]*?){2,}$", "", i.strip()) for i in con_list]
- # =====答案行格式处理====
- temp_list = [re.split(r"^((\s*<imgsrc((?!/>).)*?/>\s*)+)", v.strip(), maxsplit=1)[1::3]
- if re.match(r'(\s*<imgsrc((?!/>).)*?/>\s*)+?(参考|考试|试[题卷]|物理|理综|数学|化学|生物)'
- r'(答案|解析|答案[及与和]评分(标准|意见|细则))\s*$'
- r'|(\s*<imgsrc((?!/>).)*?/>\s*)+?评分标准'
- r'|(\s*<imgsrc((?!/>).)*?/>\s*)+?(参考|考试|试[题卷])'
- r'(答案|解析|答案[及与和]评分(标准|意见|细则))\s*(物理|理综|数学|化学|生物)?\s*$',
- re.sub(r"[上下]?学[年期]|[\d—【】..、、::(())年\s]|[中大]学|模拟|[中高]考|年级|[学期][末中]|[高初][一二三]", "",
- v.strip())) else [v] for v in con_list]
- con_list = sum(temp_list, [])
- # =====对可能的题号的处理==== 如2、3、4、5、 加了【fei】 # 重新修改!!!!!!!!!!
- con_list = [re.sub(r"^\s*([1-9][0-9]?\s*[..、、])", r"【fei】\1", i.strip())
- if (len(re.findall(r"(^|\s*[..、、])\s*[1-9][0-9]?\s*[..、、]", i)) >= 3
- and len(re.sub(r"[\d..、、\s]", "", i)) < 2) else i for i in con_list]
- # =====头尾清除没用的信息=====
- if con_list and re.search(r"[\u4e00-\u9fa5]|<img | style=\"text-(indent|align)"
- r"| style=\"text-decoration| class=\"dots\"|<strong>|<em>", con_list[0]) is None:
- con_list = con_list[1:]
- while con_list and re.search(r"声明[::].*?著作权属.*?所有|(邮箱|用户|日期|QQ)\s*[::].+?", con_list[-1]):
- con_list = con_list[:-1]
- return con_list, subs2src, self.new_html
- def del_no(item, item_no_type=1):
- """去开头的题号"""
- if item_no_type == 2:
- item = re.sub(r'^\n*\s*[((]\s*([1-9]|[1-9][0-9])\s*[))]\s*[..、、::]?', "", item)
- return item
- item = re.sub(r'^\n*\s*([1-9]|[1-9][0-9])\s*[..、、::]', "", item)
- return item
- def html_cleal_test(htmlf): # 不用
- html2txt = re.sub(r" ", "", htmlf.read()) # ("", " ")
- # html2txt.replace("①", "(1).").replace("②", "(2).").replace("③", "(3).")
- con_list = [re.sub(r"^\n+\s+<p>", "", ii) for ii in html2txt.split("</p>")[:-1]]
- # pprint(con_list)
- if re.search(r"[\u4e00-\u9fa5]", con_list[0]) is None:
- con_list = con_list[1:]
- return con_list
- def get_md5(image_id):
- """
- 由于hash不处理unicode编码的字符串(python3默认字符串是unicode)
- 所以这里判断是否字符串,如果是则进行转码
- 初始化md5、将image_name进行加密、然后返回加密字串
- """
- image_name = str(image_id) + str(time.time()) + str(random.random())
- image_name = image_name.encode("utf-8")
- md = hashlib.md5()
- md.update(image_name)
- return str(md.hexdigest())
- def wash_after(res_dict, item_groups, ans_groups, subject):
- """
- 1.处理最终结果多余的换行符;2.对题文中已给答案的选择填空进行替换;3.选择题的细分
- :param res_dict: [{},{},,,]
- :param item_groups: 题组; ans_groups: 答案分组
- :return:
- """
- pattern1 = re.compile(
- r"([是为点]|等于|=|=|有|存在)\s*_+((<img src=((?!/>).)*?/>|[^_;;。?!,\n])+?)(?<![==_])_+([cdkm上]?m?\s*.?[。.?]?\s*"
- r"($|<br/>|<img src|……))")
- pattern2 = re.compile(r"((有|存在|[是为])[\u4e00-\u9fa5]{0,2})\s*_+(\d+)_+\s*([\u4e00-\u9fa5,,;;。..])")
- chapter_no = {}
- option_st = 0
- is_optional = False
- option_score = 0
- select_type_id = []
- for num, sr in enumerate(res_dict):
- sr["stem"] = re.sub(r"\n[_\-\s]*密[…O•.\s]*封[….O•\s]*装?[…O•.\s]*订?[….O•\s]*线?"
- r"|\n\s*((学校|班级|姓名|座位?号|准考号|学号)[\s::_]*){2,}", "", sr["stem"])
- sr["stem"] = re.sub(r'\n\s*(第\s*[^\s]\s*卷|第[一二三四]部分)\s*([((].*?[))]|非?选择题.{,8})?\s*\n', "\n", sr["stem"])
- if num == len(res_dict) - 1: # 对拆分后的最后一道题进行特殊判断
- end_con = sr["stem"] + sr["parse"]
- if len(re.findall(r"[\u4e00-\u9fa5]", end_con)) > 1000 and (
- len(re.findall(r"\n\s*([1-9]|1[0-9])\s*[..、、].+?",
- end_con)) > 4 or len(re.findall(r"[((]\s*[))]|_{2,}", end_con)) > 6):
- sr['errmsgs'].append("原试卷格式有问题,导致本题可能包含了很多非本题的题文")
- # if not re.sub(r"[(())\n\s]", "", sr["stem"]):
- # sr['errmsgs'].append("本题没有题干,请检查题干格式是否正确")
- if "-" in str(sr["item_id"]) and sr['type'] in ["选择题", "填空题"]:
- if (not sr["key"] or sr["key"] == "见解析") and re.search("[A-H]+", re.sub("[;;、、\n(())\s]|\d+分", "", sr["parse"])):
- sr["key"] = re.sub("[;;、、\n(())\s]|\d+分", "", sr["parse"])
- sr["parse"] = ""
- # 把首尾的换行都去掉
- # sr["stem"] = table_label_cleal(re.sub(r"\n\s*","<br/>",sr.get("stem", "").lstrip()))
- # 将选择题和填空题中的题干中出现答案的情况 去掉答案
- kuo_con1 = re.search(r'([是为]|等于|[==有]|表示)\s*[((]\s*([A-Zc][A-Zc;;和与、、\s]*?)[))]\s*(.?($|\n|<br/>|<img))',
- sr["stem"])
- kuo_con2 = re.search("[((]\s*([A-Zc][A-Zc;;和与、、\s]*?)[))]\s*(.?($|\n|<br/>))", sr["stem"])
- if sr['type'].replace("题", "") in ["单选", "多选", "选择", "不定选择"]:
- # sr["type"] = "选择类"
- # 针对选择题在题文中已给出答案的处理
- if kuo_con1:
- sr["stem"] = sr["stem"].replace(kuo_con1.group(0), kuo_con1.group(1) + "( )" + kuo_con1.group(3))
- sr["key"] = kuo_con1.group(2).replace("c", "C") if not sr["key"] else sr["key"]
- elif kuo_con2:
- sr["stem"] = sr["stem"].replace(kuo_con2.group(0), "( )" + kuo_con2.group(2))
- sr["key"] = kuo_con2.group(1).replace("c", "C") if not sr["key"] else sr["key"]
- # sr['options_text'] = ""
- elif sr['type'] == '填空题':
- # sr["type"] = "解答类"
- ans_list = []
- # 针对填空题在题文中已给出答案的处理
- sub_n = 0
- while re.search(pattern1, sr["stem"]):
- blank_con1 = re.search(pattern1, sr["stem"])
- sr["stem"] = sr["stem"].replace(blank_con1.group(0),
- blank_con1.group(1) + "____" + blank_con1.group(5))
- ans_list.append(blank_con1.group(2))
- sub_n += 1
- if sub_n > 5:
- break
- while re.search(pattern2, sr["stem"]):
- blank_con2 = re.search(pattern2, sr["stem"])
- # 这里的限制条件易出错,可以再判断一下
- sr["stem"] = sr["stem"].replace(blank_con2.group(0),
- blank_con2.group(1) + "____" + blank_con2.group(4))
- ans_list.append(blank_con2.group(2))
- if re.findall(r"_{2,}", sr["stem"]):
- sr["blank_num"] = len(re.findall(r"_{2,}", sr["stem"]))
- if not sr["key"] and ans_list:
- sr["key"] = "; ".join(ans_list)
- # 换行符处理!
- sr["stem"] = sr.get("stem", "").rstrip()
- # sr["stem"] = get_equation_instr(sr["stem"])
- if "options" in sr: # 对选项部分进行格式处理
- for i in range(len(sr['options'])):
- sr['options'][i] = get_simpstr2eqn(sr['options'][i].strip())
- # sr['options'][i] = get_equation_instr(sr['options'][i].strip()).replace("\n\n", "\n").replace("\n", "<br/>")
- if "slave" in sr and sr["slave"]:
- # 带小题的大题,格式处理,高中数学没有这一功能
- for s in sr["slave"]:
- s["stem"] = s.get("stem", "").rstrip()
- s["parse"] = s.get("parse", "").strip().replace("解答:解:", "解答:").replace("解答:解:", "解答:")
- s["key"] = s.get("key", "").strip()
- # sr["slave"] = sr.get("slave", "").replace("\n", "<br>")
- else:
- # s["parse"] = css_conflict_deal(s["parse"]) # "css 冲突标签处理"
- sr["parse"] = sr.get("parse", "").lstrip()
- sr["parse"] = re.sub("^【解[答析]】\s*", "", sr["parse"])
- # sr["parse"] = get_equation_instr(sr["parse"])
- sr["key"] = sr.get("key", "").lstrip()
- # sr["key"] = get_equation_instr(sr["key"])
- if not sr["parse"] and not sr["key"]: # 答案和解析都没有
- sr["parse"] = ""
- sr["key"] = ""
- # sr['errmsgs'].append("本题缺少答案和解析")
- elif not sr["key"] and sr["parse"]:
- sr["key"] = "见解析"
- elif re.sub("见解析|略|空|无|没有|答案", "", sr["key"]) and not sr["parse"]:
- sr["parse"] = ""
- # if "本选做题缺少解析" not in sr['errmsgs'] and "本题缺少解析" not in sr['errmsgs']:
- # sr['errmsgs'].append("本题缺少解析")
- # 辅助标签处理
- # sr["analysis"] = ""
- if "analy" in sr: # 存在题目分析时,将其放在解析里
- # sr["analy"] = sr.get("analy", "").strip().replace("\n\n", "\n")
- if len(sr["analy"].replace(" ", "")) >= 10:
- sr["parse"] = "【分析】"+sr["analy"] + "\n【详解】" + sr["parse"]
- del sr["analy"]
- if "chapter" in sr: # 如选修4-5:不等式选讲
- if sr['item_id'] + 1 <= len(res_dict):
- chapter_no[sr['item_id']] = sr["chapter"]
- del sr["chapter"]
- # 是否为选做题"is_optional",两种形式不会同时出现
- if "option_st" in sr: # 带有此标签的后面的题目都是选做题option_score
- # option_st = sr['item_id']
- # is_optional = True
- # if "," in sr["option_st"]:
- # option_score = int(sr["option_st"].split(",")[-1])
- del sr["option_st"]
- # 将选择题改为单选或多选,"is_multiple_choice"
- sr['type'] = re.sub("([单多])项选择题?", r"\1选题", sr['type'])
- sr['type'] = sr['type'].replace("题题", "题") # .replace("简答", "解答")
- # sr['type'] = re.sub("(计算|简答)题?", "解答题", sr['type'])
- if sr['type'] in ["选择", "选择题"]: # 有的科目只有选择题,不分单选和多选
- if len(re.findall("[A-Z]", sr["key"])) > 1:
- sr['type'] = '多选题'
- elif len(re.findall("[A-Z]", sr["key"])) == 1:
- sr['type'] = '单选题'
- info_x = re.search("^[((](多)选题?[))]", sr["stem"].replace(" ", ""))
- if info_x:
- sr['type'] = '{}选题'.format(info_x.group(1))
- # if "options" in sr:
- # sr['type'] = '选择'
- # else:
- # if re.search("_{2,}", str(sr)):
- # sr['type'] = '填空'
- # else:
- # sr['type'] = '解答'
- if sr['type'] == '多选题':
- if len(re.findall("[A-Z]", sr["key"])) == 1:
- sr['errmsgs'].append("本题答案个数与题型(多选题)不符")
- # sr["is_multiple_choice"] = 'true'
- elif sr['type'] == '单选题':
- # sr["is_multiple_choice"] = 'false'
- if "options" in sr and len(sr["options"]) > 4:
- sr['errmsgs'].append("选项个数多于4个,与题型(单选题)不符")
- if len(re.findall("[A-Z]", sr["key"])) > 1:
- sr['errmsgs'].append("本题答案个数与题型(单选题)不符")
- # elif sr['type'] == '不定选择题':
- # if len(re.findall("[A-Z]", sr["key"])) > 1:
- # sr['type'] = '多选题'
- # elif len(re.findall("[A-Z]", sr["key"])) == 1:
- # sr['type'] = '单选题'
- # else:
- # sr['type'] = '选择题'
- # if "缺少答案" not in "".join(sr['errmsgs']):
- # sr['errmsgs'].append("本题缺少答案")
- elif sr['type'].replace("题", "") in ["单空", "多空", "填空"]:
- sr['type'] = "填空题"
- elif subject != "语文" and sr['type'] not in ["选择", "选择题"]:
- sr['type'] = "解答题"
- # """按照原先高中数学解析的最后输出格式整理输出"""
- # sr["type"] = sr['type'].replace("非选择", "解答").replace("题题", "题") # print(“)
- sr["topic_num"] = sr['item_id']
- sr['errmsgs'] = ";".join(sr['errmsgs'])
- sr["parse"] = re.sub(r"试题【([分解]析)】", r"试题\1:", sr["parse"]) # 解析
- sr["key"] = re.sub("([;;]|<br/>)\s*$", "", sr["key"])
- if 'susp_pic' in sr:
- del sr['susp_pic']
- if 'is_optional' in sr:
- del sr['is_optional']
- if 'spliterr_point' in sr:
- del sr['spliterr_point']
- if 'score' in sr:
- del sr["score"]
- del sr['item_id']
- # ---------------------字符串公式处理--------------------------------
- # sr["stem"] = get_equation_instr(sr["stem"])
- # sr["key"] = get_equation_instr(sr["key"])
- # sr["parse"] = get_equation_instr(sr["parse"])
- # if "options" in sr:
- # sr["options"] = list(map(get_equation_instr, sr["options"]))
- # -----------------------------------------------------------------------
- # pprint(res_dict)
- if item_groups and item_groups["is_groups"]:
- print("item_groups:", item_groups)
- print("ans_groups:", ans_groups)
- res_dict = stems_to_groups.regroup(res_dict, item_groups, ans_groups)
- else:
- for one_res in res_dict:
- one_res = parse_split2group(one_res)
- if "slave" in one_res and one_res["slave"]: # 带小问的试题题文也设置一下字体
- one_res['type'] = '小题多问类'
- one_res["stem"] = re.sub(r'(<p style="text-indent:.*?">\n*|<p style="text-align: center;?">\n*'
- r'|<p style="text-align: right;?">\n*)([^\n]+?)',
- r'\1<span style="font-family:楷体;">\2',
- one_res["stem"])
- elif "options" in one_res and one_res["options"]:
- one_res['type'] = '选择类'
- else:
- one_res['type'] = '解答类'
- if re.search("(阅读|针对|结合).{,4}[资材]料|(\n|^)\s*材料一\s", one_res['stem']):
- one_res["stem"] = re.sub(r'(<p style="text-indent:.*?">\n*|<p style="text-align: center;?">\n*'
- r'|<p style="text-align: right;?">\n*)([^\n]+?)',
- r'\1<span style="font-family:楷体;">\2',
- one_res["stem"])
- # pprint(res_dict)
- # 换行符替换
- convert_huanhang(res_dict)
- # ------------------------------------------------------------------------
- # if chapter_no: # 章节标签下移一位
- # for c, v in chapter_no.items():
- # res_dict[c]["chapter"] = v
- # 选做题"option_str"处理
- # if select_type_id:
- # for s in select_type_id:
- # if len(select_type_id) == 2:
- # res_dict[s - 1]['option_str'] = "2选1"
- # elif len(select_type_id) == 4:
- # res_dict[s - 1]['option_str'] = "4选2"
- # else:
- # res_dict[s - 1]['errmsgs'] += ";<br/>选做题不是“2选1”和“4选2”类型"
- # if option_st:
- # print("option_st:", option_st)
- # for s in range(option_st, len(res_dict)):
- # if (len(res_dict) - option_st) == 2:
- # res_dict[s]['option_str'] = "2选1"
- # elif (len(res_dict) - option_st) == 4:
- # res_dict[s]['option_str'] = "4选2"
- # else:
- # res_dict[s]['errmsgs'] += ";<br/>选做题不是“2选1”和“4选2”类型"
- # 再解析中的新图片上传腾讯云
- # 再设置一个入库接口,点击入库,才开始从本地上传图片
- return res_dict
- def convert_huanhang(items_list):
- """
- 递归 换行符替换:\n --> <br/>
- :param items_list:
- :return:
- """
- if isinstance(items_list, list):
- for k, one_i in enumerate(items_list):
- items_list[k] = convert_huanhang(one_i)
- elif isinstance(items_list, dict):
- for k, v in items_list.items():
- if k == "answer_type" and type(v) == str:
- items_list[k] = configs.answer_type[v]
- else:
- items_list[k] = convert_huanhang(v)
- elif isinstance(items_list, str):
- items_list = items_list.strip().replace("\n\n", "\n")
- items_list = re.sub('\n*(<p style=".*?">\n*)$', "", items_list)
- items_list = re.sub(r'(<p style=".*?">)\n+', r"\1", items_list)
- items_list = re.sub(r'(<p style=".*?">)(((?!</p>).)*?)\n+(</t[rd]>)', r"\1\2</p>\4", items_list)
- items_list = re.sub(r'(<p style=".*?">.+?)\n[\n\s]*(<img\s)', r"\1</p>\n\2", items_list)
- while re.search(r'(<p style=".*?">[^\n]+?)\n[\n\s]*(<p style=".*?">|<table>)', items_list, flags=re.S):
- items_list = re.sub(r'(<p style=".*?">[^\n]+?)\n[\n\s]*(<p style=".*?">|<table>)',
- r"\1</p>\2", items_list, flags=re.S)
- items_list = re.sub(r'(<p style=".*?">)(((?!</p>).)*?)\n*$', r"\1\2</p>", items_list)
- items_list = re.sub(r'(<span style="font-family:楷体;?">)(((?!</p>).)*?)</p>', r"\1\2</span></p>", items_list)
- # 将\n 换为 <p></p>
- items_list = linefeed2p(items_list)
- return items_list.replace("\n", "<br/>")
- else:
- return items_list
- return items_list
- def linefeed2p(item):
- """
- 换行标签替换为<p></p>标签,表格内的还需单独处理
- :return: str
- """
- # def subp_table(ss): # 表格里换行标签的处理,先看看情况是否需要处理
- if re.sub(r'<table>.*?</table>',"", item).count("\n") > 1:
- subs2table = {}
- all_table = re.findall(r'<table>.*?</table>', item, flags=re.S)
- for k, v in enumerate(all_table):
- subs2table["<t{}b>".format(str(k))] = v
- item = item.replace(v, "<t{}b>".format(k))
- lines = item.split("\n")
- newlines = [line if re.search(r"^<p style=|^<p>|</p>$", line) else "<p>{}</p>".format(line) for line in lines]
- item = "".join(newlines)
- if subs2table:
- item = re.sub(r"|".join(subs2table.keys()), lambda x: subs2table[x.group()], item)
- return item
- def css_conflict_deal(item):
- """
- 针对<a, <p 符号 在前端显示被过滤掉的问题:对“<”左右加$, 注意条件:“<”前$为双数时加,
- :return: str
- """
- # item = item.replace("<", "<").replace(">", ">") # 2021-8-24
- # item = re.sub("<(?!img src)", "<", item) # 还有表格
- item = item.replace("$<$", "【*_*】")
- item = re.sub("<br\s*/?>", "\n", item)
- item = re.sub(r"<(/?su[bp])>", r"【\1】", item)
- item = re.sub(r"<(/?span|p style=|/?p>|/?strong>|/?em>)", r"【\1", item)
- if re.search(r"(?<!\\\()<", item):
- n1=0
- n2=0
- for i in re.finditer("<(?!img)", item):
- if item[:i.start()+2*n1+4*n2].count("$") % 2 == 0:
- item = item[:i.start()+2*n1+4*n2] + "$<$" + item[i.start()+1+2*n1+4*n2:]
- n1 += 1
- else:
- item = item[:i.start() + 2 * n1+4*n2]+" \lt " + item[i.start()+1+2*n1+4*n2:]
- n2 += 1
- item = item.replace("【*_*】", "$<$")
- while re.search(r"\\\(.*?\$<\$.*?\\\)", item):
- item = re.sub(r"(\\\(.*?)\$<\$(.*?\\\))", r"\1 \lt \2", item)
- item = re.sub(r"【(/?su[bp])】", r"<\1>", item)
- item = re.sub(r"【(/?span|p style=|/?p>|/?strong>|/?em>)", r"<\1", item)
- return item
- def insert_sort2get_idx(item_list, num):
- """
- :param item_list: 拍好序的列表
- :param num: 插入的数值
- :return: 插入的位置
- """
- add_n = 0
- for i in range(len(item_list)):
- if num > item_list[i]:
- add_n += 1
- else:
- break
- return add_n
- # def find_seq_num(num_list):
- # """
- # 针对切分题号时切错的序号进行纠正,考虑序号是连续且正常的情况下
- # 将连续的数字进行分组
- # :param num_list:输入[3, 4, 8, 9, 12, 13, 14]
- # :return: [[3, 4],[8, 9],[12, 13, 14]]
- # """
- # seq_ranges = []
- # for k, g in groupby(enumerate(num_list), lambda x: x[0] - x[1]):
- # group = (map(itemgetter(1), g))
- # group = list(map(int, group))
- # seq_ranges.append(group)
- # return seq_ranges
- # def del_exception_value(item_list):
- # """
- # 去列表中的异常值,题目越多,越容易突出异常值
- # :return:
- # """
- # import numpy as np
- # max_v = max(item_list)
- # arr_mean = np.mean(item_list) # 均值
- # arr_var = np.var(item_list) # 方差
- # while max_v > len(item_list)+4:
- # item_list.remove(max_v)
- # print(item_list)
- # arr_mean = np.mean(item_list) # 去最大值后的均值
- # arr_var = np.var(item_list) # 去最大值后的方差
- # max_v = max(item_list)
- # # print("均值与方差:",arr_mean,arr_var)
- # if abs((item_list[-1] - item_list[0] + 1) - len(item_list)) <= 3:
- # return item_list
- # else:
- # exception_value = []
- # for i in item_list:
- # # print(abs((i - arr_mean) / arr_var), i)
- # if(abs((i - arr_mean)/arr_var)) > 0.3:
- # exception_value.append(i)
- # right_seq = [i for i in item_list if i not in exception_value]
- # return right_seq
- def pic_transfer(con_list):
- aft_opt = [] # 针对选项后是题目图片的情况,进行移位
- if "\n" in con_list[-1]:
- ccon = re.split("\n+", con_list[-1])
- while re.match("<img src=", ccon[-1]) and len(ccon) > 1:
- aft_opt.insert(0, ccon[-1])
- ccon = ccon[:-1]
- if aft_opt:
- con_list[0] += "\n" + "\n".join(aft_opt)
- con_list[-1] = "\n".join(ccon)
- con_list[0] = re.sub(r"\(\d+分\)", "", con_list[0][:9]) + con_list[0][9:]
- return con_list
- def judge_split_error(item_list):
- """
- 转对试卷切分后的小题判断是否存在切分错误的情况,能纠错就纠错,不能则删除
- :return:
- """
- # for k, v in enumerate(item_list):
- # if k>0 and v['item_id'] - item_list[k-1]['item_id']>1:
- # if
- if __name__ == '__main__':
- # -------------生成requirements.txt---------------
- # pip freeze > requirements.txt
- # import os, sys
- #
- # project_root = os.path.dirname(os.path.realpath(__file__)) # 找到当前目录
- # print(project_root)
- #
- # # 找到解释器,虚拟环境目录
- # python_root = sys.exec_prefix
- # print(python_root)
- #
- # # 拼接生成requirements命令
- # command = python_root + '\Scripts\pip freeze > ' + project_root + '\\requirements.txt'
- # print(command)
- #
- # # 执行命令。
- # os.system(command)
- # ----------------一键安装 requirements.txt------------
- # pip install -r requirement.txt
- # python_root + '\Scripts\' + pip install -r requirements.txt
- # import os
- # rrr=os.path.basename(r"http:/pstatic.dev.xueping.com/data/word/2020/08/12/5f338d18e2cce.docx")
- # print(rrr)
- # item = "<a 我没发你的接口 $2366<a$ <a 我没发你的接口 $2366<a$ <img 我没发你的接口 $2366<a$ <a 我没发你的接口 $2366<a$ <a 我没发你的接口 $2366<a$"
- # item = r"2.下列选项中,使不等式\( x<\frac{1}{x}< x_{2} \)"
- # ww = css_conflict_deal(item)
- # print(ww)
- # -----------------
- p1 = r"C:\Users\Administrator\Desktop\temp\62314b31a7d375f4518b9afd.html"
- # t1 = open(p1,'r',encoding="utf8").read()
- t1 = """
- <p>7.南洋劝业会是1910年中国在南京举办的第一个世界博览会,历时达半年,中外30多万人参观。如表是南洋劝业会“物产会”展品目录,由此可知</p>
- <table border="1">
- <tbody>
- <tr>
- <td>
- <p> </p>
- </td>
- <td>分类</td>
- <td>具体内容</td>
- </tr>
- <tr>
- <td rowspan="6">天产品</td>
- <td>农业部</td>
- <td>五谷、园蔬、树艺、储藏、器具、肥料、水利、益虫害虫标本</td>
- </tr>
- <tr>
- <td>蚕桑部</td>
- <td>茧、丝、桑种标本、蚕种标本、器具、场室模型</td>
- </tr>
- <tr>
- <td>水产部</td>
- <td>麟醫、介甲、两栖、腔囊、植物、储藏、器具、舟船模型</td>
- </tr>
- <tr>
- <td>药材部</td>
- <td>植物、动物、金石、制合器具、储藏器具</td>
- </tr>
- <tr>
- <td>矿采部</td>
- <td>五金、石炭、杂矿、采矿器具、炼冶器具、山场模型</td>
- </tr>
- <tr>
- <td>狩猎部</td>
- <td>皮革、牙角、毛羽、器械、各种标本</td>
- </tr>
- <tr>
- <td rowspan="8">工艺品</td>
- <td>染织部</td>
- <td>漂染、机织、机器、场舍模型</td>
- </tr>
- <tr>
- <td>服装部</td>
- <td>衣服、冠履、带配、陈设、装饰、各种制造之器具</td>
- </tr>
- <tr>
- <td>陶磁(瓷)部</td>
- <td>陶器、磁(瓷)器、土器、制造器具、窑厂模型</td>
- </tr>
- <tr>
- <td>髹漆部</td>
- <td>雕填、磨甸、彩绘、八宝、器具、工场模型</td>
- </tr>
- <tr>
- <td>琉璃、珐琅部</td>
- <td>琉璃、珐琅、景泰蓝、荡磁(瓷)</td>
- </tr>
- <tr>
- <td>竹木、笺扇部</td>
- <td>竹器、木器、藤器、柳条器、竹簧器、笺纸、扇、画纸</td>
- </tr>
- <tr>
- <td>玉石部</td>
- <td>玉器、石器、器具、工场模型</td>
- </tr>
- <tr>
- <td>牙角、鞣革部</td>
- <td>牙器、角器、骨器、马尾器、牛革器、马革器、羊革器、鹿革器</td>
- </tr>
- </tbody>
- </table>
- <p>A.工业体系已经形成B.精耕细作持续繁荣</p>
- <p>C.近代工业发展缓慢D.经济推动文化变迁</p>
- <p>【答案】C</p>
- """
- res = HtmlWash(t1,'11111111',"高中物理").html_cleal()
- print(res)
|