field_eq2latex.py 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. #!/usr/bin/env/python
  2. # -*- coding:utf-8 -*-
  3. """
  4. 域公式转latex
  5. """
  6. import re, os
  7. import configs
  8. from pprint import pprint
  9. from func_timeout import func_set_timeout
  10. SUB = {"A":"Ⓐ",
  11. "V":"Ⓥ",
  12. "W":"Ⓦ",
  13. "X":"Ⓧ",
  14. "G":"Ⓖ",
  15. }
  16. # def get_latex(item):
  17. # if r"$eq \\f(" in item:
  18. # item = re.sub(r"\$eq \\\\f\((.+?),(.+?)\)", r"$\\frac{\1}{\2}", item)
  19. #
  20. # if r"$eq \\r(" in item:
  21. # item = re.sub(r"\$eq \\\\r\((.+?)\)", r"$\sqrt{\1}", item)
  22. #
  23. # if "$eq \\\\o\\\\" in item:
  24. # while re.search(r"\$eq \\\\o\\\\al\((.+?),(.*?)\)", item):
  25. # ss = re.search(r"\$eq \\\\o\\\\al\((.+?),(.*?)\)", item)
  26. # # 将非变量的{}修改成{{}}
  27. # s1 = "$_{{{sub}}}^{{{sup}}}".format(sub=ss.group(2), sup=ss.group(1))
  28. # s1 = re.sub("</?su[bp]>|\s", "", s1)
  29. # if not ss.group(2):
  30. # eq_info = re.match(r"\$\s*<sub>(.+?)</sub>", item[ss.end():])
  31. # if eq_info:
  32. # s1 = "$_{{{sub}}}^{{{sup}}}$".format(sub=eq_info.group(1), sup=ss.group(1))
  33. # s1 = re.sub("</?su[bp]>|\s", "", s1)
  34. # item = item[:ss.start()] + s1 + item[ss.end()+eq_info.end():]
  35. # # return re.sub("</?su[bp]>|\s", "", s1)
  36. # else:
  37. # item = item[:ss.start()] + s1 + item[ss.end():]
  38. # else:
  39. # item = item[:ss.start()] + s1 + item[ss.end():]
  40. #
  41. # # s1 = "$_{{{sub}}}^{{{sup}}}".format(sub=ss.group(2), sup=ss.group(1))
  42. # # return re.sub("</?su[bp]>|\s", "", s1)
  43. # # item = re.sub(r"\$eq \\\\o\\\\al\((.+?),(.*?)\)", sub1, item)
  44. #
  45. # ac_info = re.search(r"\$eq \\\\o\\\\ac\(○,\s*([A-Z])\)", item)
  46. # if ac_info:
  47. # if ac_info.group(1) in SUB.keys():
  48. # item = item.replace(ac_info.group(0), SUB.get(ac_info.group(1)))
  49. #
  50. # return item
  51. # @func_set_timeout(3)
  52. def get_latex0(item):
  53. while "$eq \\\\f(" in item or "$eq \\\\r(" in item or re.search("【域公式】.*?\\\\o\\\\", item):
  54. if "$eq \\\\f(" in item:
  55. # item = re.sub(r"\$eq \\\\f\((((?!\\\\[fr]).)+?),(.+?)\)", r"$\\frac{\1}{\2}", item)
  56. item = re.sub(r"(【域公式】.*?)\\\\f\((((?!\\\\[fr]\().)+?),(((?!\\\\[fr]\().)+?)\)",
  57. r"\1\\frac{\2}{\4}", item)
  58. if "$eq \\\\r(" in item:
  59. item = re.sub(r"(【域公式】.*?)\\\\r\((((?!\\\\[fr]\().)+?)\)", r"\1\sqrt{\2}", item)
  60. if re.search("【域公式】.*?\\\\o\\\\", item): # if "$eq \\\\o\\\\" in item:
  61. while re.search(r"【域公式】.*?\\\\o\\\\al\((.+?),(.*?)\)", item):
  62. ss = re.search(r"(【域公式】.*?)\\\\o\\\\al\((.+?),(.*?)\)", item)
  63. # 将非变量的{}修改成{{}}
  64. s1 = "_{{{sub}}}^{{{sup}}}".format(sub=ss.group(3), sup=ss.group(2))
  65. s1 = re.sub("</?su[bp]>|\s", "", s1)
  66. if not ss.group(3):
  67. eq_info = re.match(r"\$\s*<sub>(.+?)</sub>", item[ss.end():])
  68. if eq_info:
  69. s1 = "_{{{sub}}}^{{{sup}}}$".format(sub=eq_info.group(1), sup=ss.group(2))
  70. s1 = re.sub("</?su[bp]>|\s", "", s1)
  71. item = item[:ss.start()] + ss.group(1) + s1 + item[ss.end()+eq_info.end():]
  72. # return re.sub("</?su[bp]>|\s", "", s1)
  73. else:
  74. item = item[:ss.start()] + ss.group(1) + s1 + item[ss.end():]
  75. else:
  76. item = item[:ss.start()] + ss.group(1) + s1 + item[ss.end():]
  77. # s1 = "$_{{{sub}}}^{{{sup}}}".format(sub=ss.group(2), sup=ss.group(1))
  78. # return re.sub("</?su[bp]>|\s", "", s1)
  79. # item = re.sub(r"\$eq \\\\o\\\\al\((.+?),(.*?)\)", sub1, item)
  80. ac_info = re.search(r"\$eq \\\\o\\\\ac\(○,\s*([A-Z])\)", item)
  81. if ac_info:
  82. if ac_info.group(1) in SUB.keys():
  83. item = item.replace(ac_info.group(0), SUB.get(ac_info.group(1)))
  84. return item.replace("【域公式】$eq ", "$")
  85. # @func_set_timeout(5)
  86. def zifu_match_combine(split_eq):
  87. """
  88. 递归函数,将成对括号进行组合,目前先按成对的括号进行转化
  89. :param split_eq:
  90. :return:
  91. """
  92. if len(split_eq) < 4 or ")" not in split_eq or "(" not in split_eq:
  93. return split_eq
  94. for k, i in enumerate(split_eq):
  95. if i == ")":
  96. for subk, j in enumerate(split_eq[:k][::-1]):
  97. if j == "(":
  98. # print(split_eq[k - subk - 1 - 1])
  99. bef_left_kuohao = split_eq[k - subk - 1 - 1]
  100. if bef_left_kuohao == "\\f":
  101. # dou_index = split_eq[k-subk-1-1:k+1].index(',')+k-subk-2
  102. # bb = split_eq[k - subk - 1 - 1:k + 1]
  103. info1 = re.search(r"\\f\((.*?),(.*?)\)$", "".join(split_eq[k - subk - 1 - 1:k + 1]))
  104. if info1:
  105. new_s = "\\frac{{{one}}}{{{two}}}".format(one=info1.group(1), two=info1.group(2))
  106. new_split_eq = split_eq[:k - subk - 1 - 1]
  107. if new_split_eq and new_split_eq[-1] == "(":
  108. new_s = "{" + new_s + "}"
  109. new_split_eq.append(new_s)
  110. new_split_eq.extend(split_eq[k + 1:])
  111. return zifu_match_combine(new_split_eq)
  112. elif bef_left_kuohao == "\\r":
  113. info1 = re.search(r"\\r\((.*?)\)$", "".join(split_eq[k - subk - 1 - 1:k + 1]))
  114. if info1:
  115. new_s = "\sqrt{{{}}}".format(re.sub("^\s*,", "", info1.group(1)))
  116. new_split_eq = split_eq[:k - subk - 1 - 1]
  117. if new_split_eq and new_split_eq[-1] == "(":
  118. new_s = "{" + new_s + "}"
  119. new_split_eq.append(new_s)
  120. new_split_eq.extend(split_eq[k + 1:])
  121. return zifu_match_combine(new_split_eq)
  122. elif bef_left_kuohao in ['\\o\\al', '\\s']:
  123. info1 = re.search(r"(\\o\\al|\\s)\((.*?),(.*?)\)$", "".join(split_eq[k - subk - 1 - 1: k + 1]))
  124. if info1:
  125. new_s = "_{{{sub}}}^{{{sup}}}".format(sub=info1.group(3), sup=info1.group(2))
  126. new_s = re.sub("</?su[bp]>|\s", "", new_s)
  127. new_split_eq = split_eq[:k - subk - 1 - 1]
  128. new_split_eq.append(new_s)
  129. new_split_eq.extend(split_eq[k + 1:])
  130. return zifu_match_combine(new_split_eq)
  131. elif bef_left_kuohao == '\\x\\to':
  132. info1 = re.search(r"\\x\\to\((.*?)\)$", "".join(split_eq[k - subk - 1 - 1:k + 1]))
  133. if info1:
  134. new_s = "\\bar{{{}}}".format(info1.group(1))
  135. new_split_eq = split_eq[:k - subk - 1 - 1]
  136. if new_split_eq and new_split_eq[-1] == "(":
  137. new_s = "{" + new_s + "}"
  138. new_split_eq.append(new_s)
  139. new_split_eq.extend(split_eq[k + 1:])
  140. return zifu_match_combine(new_split_eq)
  141. else:
  142. new_s = "".join(split_eq[k - subk - 1 - 1: k + 1])
  143. new_split_eq = split_eq[:k - subk - 1 - 1]
  144. new_split_eq.append(new_s)
  145. new_split_eq.extend(split_eq[k + 1:])
  146. return zifu_match_combine(new_split_eq)
  147. # @func_set_timeout(36)
  148. def get_latex(item, is_reparse=0, wordid="123456"):
  149. """
  150. 第一通道:
  151. 将文本中的域代码字符串能转化latex的先转化,不能转化的就暂时用域代码格式
  152. 第二通道:
  153. 再解析时,遇到域代码,将域代码转图片处理
  154. 考虑先转化:根式、分式、上下标、to、\s
  155. :param item:
  156. :return:
  157. """
  158. is_first = 1
  159. item = item.replace("\\uf028", "(").replace("\\uf029", ")") # 2020-6-21
  160. new_item = ""
  161. # semi_succ_dict = {}
  162. while re.findall("(【域公式:[^【]*?】)", item):
  163. all_eqs1 = re.findall("(【域公式:[^【]*?】)", item) # 遇到嵌套的域公式,无法获取完整,故加【
  164. all_eqs = list(set(all_eqs1))
  165. all_eqs.sort(key=all_eqs1.index)
  166. print(all_eqs)
  167. new_eqs = []
  168. fail_n = 0
  169. for eq in all_eqs:
  170. raw_eq = eq.replace("\\\\", "\\").replace(" \R", " \\r")
  171. eq = raw_eq.replace("eq ", "").replace("【域公式:", "").replace("】", "")
  172. split_eq = re.split(r"(\\f|\(|\)|\\r|\\o\\al|\\x\\to|\\s|,)", eq)
  173. split_eq = [i for i in split_eq if i]
  174. res_eq = zifu_match_combine(split_eq)
  175. # print(res_eq, split_eq)
  176. try:
  177. if "".join(res_eq) == "".join(split_eq): # 转失败
  178. fail_n += 1
  179. new_eqs.append(raw_eq)
  180. elif re.search(r"\\[a-zA-Z\d]{1,5}\(", "".join(res_eq)): # 没有完全转成功
  181. fail_n += 1
  182. new_eqs.append(raw_eq)
  183. # semi_succ_dict[raw_eq] = "【域公式:eq {}】".format("".join(res_eq))
  184. # new_eqs.append("【域公式:eq {}】".format("".join(res_eq)))
  185. else:
  186. # mathjax不能渲染sub和sup
  187. new_eq = "".join(res_eq)
  188. def deal2(yy):
  189. new_y = yy.group(2)
  190. if yy.group(1) == "<sub>":
  191. new_y = "_{" + yy.group(2) + "}"
  192. if yy.group(1) == "<sup>":
  193. new_y = "^{" + yy.group(2) + "}"
  194. return new_y
  195. new_eq = re.sub("(<sub>)(.+?)</sub>", deal2, new_eq)
  196. new_eq = re.sub("(<sup>)(.+?)</sup>", deal2, new_eq).strip()
  197. if not is_first: # 如果不是第一轮转化,则将前面转化后的$去掉
  198. new_eq = re.sub(r"(?<!\\)\$", "", new_eq)
  199. new_eqs.append("${}$".format(new_eq))
  200. except:
  201. fail_n += 1
  202. new_eqs.append(raw_eq)
  203. if fail_n == len(all_eqs): # 防止死循环
  204. break
  205. eq_repl_dict = dict(zip(all_eqs, new_eqs))
  206. # print('-------------',eq_repl_dict)
  207. for k, v in eq_repl_dict.items():
  208. item = item.replace(k, v)
  209. is_first = 0
  210. # 对于转latex失败的域公式走第二通道:转图片
  211. # 嵌套的情况,里层域公式转latex成功,外层转失败,怎么办
  212. # if is_reparse and "【域公式" in item:
  213. # file_path = configs.IMG_FOLDER + '/' + str(wordid) + '/' + "field_eq"
  214. # if not os.path.exists(file_path):
  215. # os.makedirs(file_path)
  216. # new_eqs2raw = {} # 域代码_原始文本
  217. # for i in re.finditer("【域公式:(.*?)】", item):
  218. # if re.search(r"\\sqrt|\\frac|\\bar", i.group(1)) is None: # 不能包含latex命令
  219. # if "【" in i.group(1): # 嵌套,则按上面提取的域公式不完整
  220. # cout = i.group(1).count("【") # 统计【个数
  221. # try: # 根据嵌套的“【”找到最外层的“】”
  222. # raw_eq = i.group(0)+"】".join(item[i.end():].split("】")[:cout])+"】" # 拿到完整样式
  223. # eqs = i.group(1) + "".join(item[i.end():].split("】")[:cout])
  224. # eqs = "eq " + eqs.replace("【域公式:", "").replace("【", "").replace("eq ", "")
  225. # eqs = re.sub("<sub>(.+?)</sub>", r"\s(,\1)", eqs)
  226. # eqs = re.sub("<sup>(.+?)</sup>", r"\s(\1,)", eqs)
  227. # new_eqs2raw[eqs]=raw_eq
  228. # except:
  229. # pass
  230. # else:
  231. # eqs = re.sub("<sub>(.+?)</sub>", r"\s(,\1)", i.group(1))
  232. # eqs = re.sub("<sup>(.+?)</sup>", r"\s(\1,)", eqs)
  233. # new_eqs2raw[eqs] = i.group(0)
  234. # else:
  235. # print("域公式中含latex表达式!!!")
  236. # new_eqs = list(new_eqs2raw.keys())
  237. # new_eqs.append(file_path)
  238. # eqcode = "】【".join(new_eqs)
  239. # try:
  240. # requests.get(r"http://localhost:9001/FieldEq/Eq2Png/?eqcode=" + eqcode, timeout=30)
  241. # except:
  242. # pass
  243. # # 在生成图片的文件夹中对应判断图片再进行替换
  244. # eq_imgs = os.listdir(file_path)
  245. # if eq_imgs:
  246. # raw_eqs2img = {}
  247. # for img in eq_imgs:
  248. # w_h_info = str(img.replace(".png", "").split("__")[-1]).split("_")
  249. # w = int(int(w_h_info[0])/1.27+1)
  250. # h = int(int(w_h_info[1])/1.27+1)
  251. # name = str(img.replace(".png", "").split("__")[0])
  252. # idn = int(name.split("_")[-1])
  253. # new_name = name + ".png"
  254. # os.rename(file_path + "/" + img, file_path + "/" + new_name)
  255. # eq_img = '<img src="{}/{}/field_eq/{}" width="{}px" height="{}px" eq-code="{}" />'\
  256. # .format(configs.new_img_ip, wordid, new_name, w, h, new_eqs[idn-1])
  257. # raw_eqs2img[new_eqs2raw[new_eqs[idn-1]]] = eq_img
  258. # if raw_eqs2img:
  259. # for k, v in raw_eqs2img.items():
  260. # item = item.replace(k, v)
  261. # new_item = new_item.replace(k, v)
  262. # else:
  263. # new_item = ""
  264. # else:
  265. # new_item = ""
  266. return item, new_item
  267. if __name__ == '__main__':
  268. import requests,json
  269. # f = "t=【域公式】$eq \\\\f(v<sub>0</sub>,a)$=【域公式】$eq \\\\f(6,1)$ s=6s, $eq \\\\r(6)$ "
  270. # print(re.sub(r"\\\\o\\\\al\((.+?),.+?\)", r"\1",f))
  271. # p1 = r"C:\Users\Python\Desktop\test\24\25.html"
  272. # html = open(p1, 'r', encoding='utf-8').read()
  273. # # print(html)
  274. # print(get_latex(html))
  275. # f = "eq \\f(\\f(1,2)×0.82,0.2×10)】【eq \\f(6,1)】【eq \\f(\\x\\to(OC)-\\x\\to(OA),2T)】【C:/Users/Python/Desktop/test/temp"
  276. # res = requests.get(r"http://localhost:9001/FieldEq/Eq2Png/?eqcode=" + f, timeout=30).text
  277. # print(json.loads(res).replace("\r\n", ""))
  278. f = "【解】解析 (1)因OB绳处于竖直方向,所以B球处于平衡状态,AB绳上的拉力为零,OB绳对小球的拉力F<sub>OB</sub>=mg. (3分)<br/>(2)A球在重力mg、水平拉力F和OA绳的拉力F<sub>OA</sub>三力作用下平衡,所以OA绳对小球的拉力F<sub>OA</sub>=【域公式:eq \\\\f(mg,cos 60°)】=2mg. (3分)<br/>(3)作用力F=mgtan 60°=【域公式:eq \\\\r(3)】mg. (3分)<br/>答案 (1)mg (2)2mg (3)【域公式:eq \\\\r(3)】mg"
  279. # f = "【域公式:eq \\f(v<sub>0</sub>,a)】"
  280. aa = get_latex(f, )
  281. print(aa)
  282. # item = "【域公式:eq \\f(【域公式:eq \\f(6,1)】,3)】geeghe】threthtrh"
  283. # new_eqs2raw = {} # 域代码_原始文本
  284. # for i in re.finditer("【域公式:(.*?)】", item):
  285. # print(i.group(0))
  286. # if re.search(r"\\sqrt|\\frac|\\bar", i.group(1)) is None: # 不能包含latex命令
  287. # if "【" in i.group(1): # 嵌套
  288. # cout = i.group(1).count("【")
  289. # try: # 根据嵌套的【找到最外层的】
  290. # raw_eq = i.group(0) + "】".join(item[i.end():].split("】")[:cout]) + "】"
  291. # eqs = i.group(1) + "".join(item[i.end():].split("】")[:cout])
  292. # eqs = "eq " + eqs.replace("【域公式:", "").replace("【", "").replace("eq ", "")
  293. # eqs = re.sub("<sub>(.+?)</sub>", r"\s(,\1)", eqs)
  294. # eqs = re.sub("<sup>(.+?)</sup>", r"\s(\1,)", eqs)
  295. # new_eqs2raw[eqs] = raw_eq
  296. # except:
  297. # pass
  298. # else:
  299. # eqs = re.sub("<sub>(.+?)</sub>", r"\s(,\1)", i.group(1))
  300. # eqs = re.sub("<sup>(.+?)</sup>", r"\s(\1,)", eqs)
  301. # new_eqs2raw[eqs] = i.group(0)