re_servicetime.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. #coding:UTF-8
  2. import re
  3. import pandas as pd
  4. from bs4 import BeautifulSoup
  5. TEST_MODE = False
  6. # before = '(?P<before>' \
  7. # '合同期限|工期/交货期/服务期|工期,\(日历天\)|工期\(交货期\)|合格工期\(天\)|服务期限\(年\)|工期\(天\)' \
  8. # '|工期要求|项目周期|工期\(交货期\)|计划工期\(服务期限\)|服务时限|履行期限|服务周期|供货期' \
  9. # '|合格工期|计划工期\(服务期\)|服务期\(日历天\)|服务,期|交货\(完工\)时间|交付\(服务、完工\)时间' \
  10. # '|交货时间|工期\(日历天\)' \
  11. # '|服务期限为|计划工期|工期要求|服务期限|服务期' \
  12. # '|投标工期|设计工期|合格服务周期|总工期|服务时间|流转期限|维护期限|服务时限|交货期|服务要求' \
  13. # '|完成时间|服务期限|中标工期|项目周期|期限要求|周期|工期|供货期|合同履行日期|计划周期|工期' \
  14. # ')'
  15. before = '(?P<before>' \
  16. '合同期限|工期/交货期/服务期|工期,|工期\(交货期\)|合格工期|服务期限|工期' \
  17. '|工期要求|项目周期|工期\(交货期\)|计划工期\(服务期限\)|服务时限|履行期限|服务周期|供货期' \
  18. '|合格工期|计划工期\(服务期\)|服务期|服务,期|交货\(完工\)时间|交付\(服务、完工\)时间' \
  19. '|交货时间|工期|质保期' \
  20. '|服务期限为|计划工期|工期要求|服务期限|服务期' \
  21. '|投标工期|设计工期|合格服务周期|总工期|服务时间|流转期限|维护期限|服务时限|交货期' \
  22. '|完成时间|服务期限|中标工期|项目周期|期限要求|周期|供货期|合同履行日期|计划周期' \
  23. '|履约期限|合同约定完成时限|合同完成日期' \
  24. ')'
  25. # ^(?!.*abc).*$ 排除abc字符串
  26. before_wuye = '(?P<before>' \
  27. '(履约期限、地点等简要信息[::])|(履约期限、地点等简要信息.{0,25}(?= [\d半一二三四五六七八九十壹两叁贰肆伍陆柒捌玖拾]+([年月日]|个月)|20[21]))' \
  28. ')'
  29. before2 = '(?P<before2>' \
  30. '自合同签订之日起至|合同签订之日起|自合同签订之日起|开工后|不超过|签订合同后|系统开发' \
  31. '|合同签订之日起至|自合同签订之日|合同签定后|自签订合同之日起|自合同签订起' \
  32. '|[自从]?合同签[订定]生效之日起|自合同签订后不超过|中选后|均为|合同签订日至|合同期' \
  33. '|.{0,1}合同签订.{0,3}|计划|从|合同签订生效之日起|本项目招标有效期' \
  34. '|[自从]?签[订定]合同(之日|后).{1,4}|[自从]?(采购)?合同签[订定](之日|后|).{1,5}|签订合同起' \
  35. '|项目的有效期限为|项目服务为|签订合同期为|合同签[订定]生效之日.{1,4}' \
  36. '|[自从]服务合同生效之日.{1,4}|[自从].{2,15}之日.{1,4}|(本次)?采购周期' \
  37. '|(项目招标)?履行期|[自从于]?合同生效之日.{1,3}|' \
  38. ')'
  39. before3 = '(?P<before3>' \
  40. '([\((]日历天[\))]|[\((]天[\))]|[\((]年[\))]|[\((]月[\))])?' \
  41. ')'
  42. charac = '(?P<charac>' \
  43. '[::,,【()】为是起暂定的有效期限]*' \
  44. ')'
  45. center = '(?P<center>' \
  46. '[自为约是起暂定的拟期从]{0,3}(\d{2,4}[-.年/]?\d{1,2}[-.月/]?\d{1,2}[日号]?[-~~起至—]+(\d{2,4}[-.年/]?)?\d{1,2}[-.月/]?\d{1,2}[日号]?|\d{2,4}年\d{1,2}月\d{1,2}[日号]|[\d半一二三四五六七八九十壹两叁贰肆伍陆柒捌玖拾]+)' \
  47. ')'
  48. number = '(?P<number>' \
  49. '[\d半一二三四五六七八九十壹两叁贰肆伍陆柒捌玖拾]+' \
  50. ')'
  51. after = '(?P<after>' \
  52. '周年|周|号|天|个月|个年|年|个日历天|日历天|日|\(日历天\)|\(天\)|周内|,日历天|工作日|个工作日|' \
  53. ')'
  54. after1 = '(?P<after1>' \
  55. '[自为约是起暂定的拟从]{0,3}\d{4}[-年/]?(\d{1,2}[-月/]?)?(\d{1,2}[日号]?)?[-~~起至—]+(\d{4}[-年/]?)?(\d{1,2}[-月/]?)?(\d{1,2}日?)?(-\d{1,2}[日号]?)?([】)]?)' \
  56. ')'
  57. after2 = '(?P<after2>' \
  58. '\d+' \
  59. ')'
  60. after3 = '(?P<after3>' \
  61. '(.{0,25}止([\d半一二三四五六七八九十壹两叁贰肆伍陆柒捌玖拾][年月日])?)' \
  62. ')'
  63. reg = re.compile(before + before3 + charac + before2 + center + after)
  64. reg1 = re.compile(before + before3 + charac + after3)
  65. reg2 = re.compile(before + before3 + charac + before2 + after1)
  66. reg3 = re.compile(before + before3 + charac + before2 + after2)
  67. reg4 = re.compile(before2[:-2]+before2[-1:] + center + after)
  68. # reg4 = re.compile(before2[:-2]+before2[-1:] + number + after)
  69. # print(before2[:-2]+before2[-1:])
  70. reg_wuye = re.compile(before_wuye + center + after)
  71. reg_not = re.compile(u'(工期延误|工期节点|工期管理|交付使用'
  72. u'|工期、)'
  73. u'|工期情况|划工期内|服务期内')
  74. reg_not1 = re.compile(u'(履行日期:见|服务期限应按|签订合同前,'
  75. u'|务期限:1、|签订日期|证金在合同签|服务期限截止'
  76. u')')
  77. # reg_not2 = re.compile(u'(截止|1\\.|1、)')
  78. reg_not2 = re.compile(u'(截止)')
  79. reg_right_digit = re.compile(u'[\d半一二三四五六七八九十壹两叁贰肆伍陆柒捌玖拾]+')
  80. reg_right_unit = re.compile(u'[-.年月日号天~~至—]')
  81. reg_error = re.compile(u'公告|发布|中')
  82. def re_serviceTime(text):
  83. if TEST_MODE:
  84. # print(chardet.detect(text))
  85. text = re.sub("\s*", "", text)
  86. text_list = []
  87. text_list.append(text)
  88. # 初始化
  89. all_output_list = []
  90. all_text_index_list = []
  91. for index in range(len(text_list)):
  92. # 初始化
  93. output_list = []
  94. input_str = text_list[index]
  95. # 替换混淆词
  96. for _reg_not in [reg_not, reg_not1, reg_not2]:
  97. match_iter = re.finditer(_reg_not, input_str)
  98. for match in match_iter:
  99. word_index = match.span()
  100. word = match.group()
  101. instead = "#" * len(word)
  102. print("word, instead, word_index", word, instead, word_index)
  103. input_str = input_str[:word_index[0]] + instead + input_str[word_index[1]:]
  104. if TEST_MODE:
  105. print("input_str", input_str)
  106. # 匹配
  107. output_list, text_index_list = re_findAllResult(reg2, input_str)
  108. if TEST_MODE:
  109. print("output_str, text_index reg2", output_list, text_index_list)
  110. if len(output_list) == 0:
  111. output_list, text_index_list = re_findAllResult(reg, input_str)
  112. if TEST_MODE:
  113. print("output_str, text_index reg", output_list, text_index_list)
  114. if len(output_list) == 0:
  115. output_list, text_index_list = re_findAllResult(reg1, input_str)
  116. if TEST_MODE:
  117. print("output_str, text_index reg1", output_list, text_index_list)
  118. if len(output_list) == 0:
  119. output_list, text_index_list = re_findAllResult(reg3, input_str)
  120. if TEST_MODE:
  121. print("output_str, text_index reg3", output_list, text_index_list)
  122. if len(output_list) == 0:
  123. output_list, text_index_list = re_findAllResult(reg4, input_str)
  124. if TEST_MODE:
  125. print("output_str, text_index reg4", output_list, text_index_list)
  126. if len(output_list) == 0:
  127. output_list, text_index_list = re_findAllResult(reg_wuye, input_str)
  128. if TEST_MODE:
  129. print("output_str, text_index reg_wuye", output_list, text_index_list)
  130. # 过滤
  131. delete_list = []
  132. for i in range(len(output_list)):
  133. output = output_list[i]
  134. # 不包含数字、单位的
  135. if not re.findall(reg_right_digit, output):
  136. delete_list.append([output, text_index_list[i]])
  137. continue
  138. if not re.findall(reg_right_unit, output):
  139. delete_list.append([output, text_index_list[i]])
  140. continue
  141. # 包含不要的字
  142. if re.findall(reg_error, output):
  143. delete_list.append([output, text_index_list[i]])
  144. continue
  145. # 类似2019年的
  146. if not re.findall("[月日天号]", output):
  147. if len(re.findall("年", output)) == 1:
  148. year_time = re.search("\d+", output)
  149. if year_time is not None and int(year_time.group()) >= 2000:
  150. print("delete output", output)
  151. delete_list.append([output, text_index_list[i]])
  152. for output, text_index in delete_list:
  153. if output in output_list:
  154. output_list.remove(output)
  155. if text_index in text_index_list:
  156. text_index_list.remove(text_index)
  157. # 添加
  158. all_output_list += output_list
  159. all_text_index_list += text_index_list
  160. index2word = []
  161. for i in range(len(all_text_index_list)):
  162. word = text[all_text_index_list[i][0]:all_text_index_list[i][1]]
  163. if i != len(all_text_index_list)-1:
  164. word = word + " "
  165. index2word.append(word)
  166. if TEST_MODE:
  167. print("index2word all_text_index_list", index2word, all_text_index_list)
  168. return index2word, all_text_index_list
  169. def re_findAllResult(reg, input, unit="", index=0):
  170. """
  171. :param reg: 正则表达式
  172. :param input: 待匹配句子
  173. :param unit: 需要加的单位
  174. :param index: 字符串拼接的开始位置
  175. :return: 正则后的字符串
  176. """
  177. # 全文下标
  178. text_index = []
  179. match1 = re.finditer(reg, input)
  180. output_list = []
  181. for i in match1:
  182. output = ""
  183. d = i.groupdict()
  184. if d.get("before"):
  185. output += d.get("before")
  186. if d.get("before3"):
  187. output += d.get("before3")
  188. if d.get("charac"):
  189. output += d.get("charac")
  190. if d.get("before2"):
  191. output += d.get("before2")
  192. if d.get("center"):
  193. output += d.get("center")
  194. if d.get("number"):
  195. output += d.get("number")
  196. if d.get("after"):
  197. output += d.get("after")
  198. if d.get("after1"):
  199. output += d.get("after1")
  200. if d.get("after2"):
  201. output += d.get("after2")
  202. if d.get("after3"):
  203. output += d.get("after3")
  204. if d.get("before") is not None:
  205. if d.get("before3") is None or d.get("before3") != "":
  206. front_len = len(d.get("before"))
  207. # print("1-", len(d.get("before")))
  208. else:
  209. front_len = len(d.get("before")) + len(d.get("charac"))
  210. # print("2-", len(d.get("before")), len(d.get("charac")))
  211. if d.get("before2") is not None:
  212. front_len += len(d.get("before2"))
  213. else:
  214. front_len = 0
  215. text_index.append([i.start()+front_len, i.end()])
  216. output_list.append(output)
  217. return output_list, text_index
  218. def calculateLen(ss, i):
  219. front_len = 0
  220. back_len = 0
  221. for index in range(i):
  222. front_len += len(ss[index])
  223. for index in range(i+1, len(ss)):
  224. back_len += len(ss[index])
  225. return front_len, back_len
  226. def extract_servicetime(text):
  227. list_servicetime = []
  228. word_list, text_index_list = re_serviceTime(text)
  229. # print(word, text_index_list)
  230. for i in range(len(text_index_list)):
  231. d = {"body": word_list[i], "begin_index": text_index_list[i][0], "end_index": text_index_list[i][1]}
  232. if len(word_list[i]) <= 35:
  233. list_servicetime.append(d)
  234. if TEST_MODE:
  235. print("list_servicetime", list_servicetime)
  236. return list_servicetime
  237. def test_from_str():
  238. # s = """
  239. # 青岛市即墨区新兴中学物业管理服务项目 信息公开 合同公告 一、合同编号:D202101110008 二、合同名称:物业管理服务项目 三、项目编码(或招标编号、政府采购计划编号、采购计划备案文号等,如有):D202101110008 四、项目名称:物业管理服务项目 五、合同主体 采购人(甲方):青岛市即墨区新兴中学 地址:新兴路288号 联系方式:0532-88509712 供应商(乙方):青岛安之信物业管理有限公司 地址:山东省青岛市即墨区振华街87号恒生源大厦5楼 联系方式:0532-88510757 15966863456 六、合同主要信息 主要标的名称:物业管理服务 规格型号(或服务要求):1、所有上岗人员均要求符合相应年龄、性别及学历标准,身体健康,品德端正,无任何违法犯罪记录。 2、门卫需24小时在岗等。 3、卫生保洁人员:负责学校公共区域卫生保洁等。 4、校园绿化人员:根据季节要求,规范养护校园植物等。 5、公共设施设备维修维护:维修 主要标的数量:1.0 主要标的单价:277200.0 合同金额:27.72 万元 履约期限、地点等简要信息:2021-01-31、即墨区新兴中学 采购方式:网上超市 七、合同签订日期:2021-01-11 八、合同公告日期:2021-01-11 九、其他补充事宜: 附件: 『查看附件』 发 布 人:青岛市即墨区新兴中学 发布时间: 2021年1月11日
  240. # """
  241. s = " 服务周期/到货期:2022年6月1日-2022年12月31日。 "
  242. print(extract_servicetime(s))
  243. def test_from_csv():
  244. df = pd.read_csv("D:/BIDI_DOC/招标方式_服务期限_提取/serviceTime_text.csv")
  245. result_list = []
  246. for index, row in df.iterrows():
  247. result = extract_servicetime(row["text"])
  248. result_list.append(str(result))
  249. df["new_word"] = pd.DataFrame(result_list)
  250. df.to_csv("D:/BIDI_DOC/招标方式_服务期限_提取/serviceTime_text_new.csv")
  251. def test_from_xlsx():
  252. df = pd.read_excel("D:/BIDI_DOC/比地_文档/service_time_error.xlsx")
  253. result_list = []
  254. for index, row in df.iterrows():
  255. text = row["dochtmlcon"]
  256. soup = BeautifulSoup(text, "lxml")
  257. text = soup.get_text(strip=True)
  258. result = extract_servicetime(text)
  259. result_list.append(str(result))
  260. df["new_word"] = pd.DataFrame(result_list)
  261. df.to_excel("D:/BIDI_DOC/比地_文档/service_time_error_new.xlsx", index=False)
  262. if __name__ == '__main__':
  263. test_from_str()