| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277 |
- # -*- coding: utf-8 -*-
- """属性处理纯函数(PURE FUNCTIONS)。
- 按 ARCHITECTURE.md Phase 6 拆分建议,从 ``interface/getAttributes.py`` 迁出
- 被 ``predictors/`` 反向导入的纯函数,消除 ``predictors ↔ interface.getAttributes``
- 循环依赖。
- 原位置:``interface/getAttributes.py``:
- - ``turnMoneySource`` — 资金来源文本归一(原 3335-3368 行)
- - ``get_days_between`` — 计算两日期天数差(原 4211-4228 行)
- - ``extract_serviceTime`` — 解析服务期(起止日期/天数)(原 4230-4407 行)
- 迁移原因:
- - ``predictors/table_prem.py`` 导入 ``extract_serviceTime``
- - ``predictors/approval.py`` 导入 ``turnMoneySource``
- - ``template_extractor.py`` 导入 ``extract_serviceTime``
- - ``interface/predictor.py`` 导入 ``turnMoneySource``, ``extract_serviceTime``
- 将这些函数下沉到 ``common/`` 层,使 ``predictors/`` 只依赖 ``common/``,
- 不再反向依赖 ``interface.getAttributes``(属于 assembly 层)。
- 按 ARCHITECTURE.md §4.3 依赖方向约束:
- common 可被各层引用,但不反向依赖 pipeline / predictors / assembly / rules。
- ``interface/getAttributes.py`` 仍 re-export 以上全部名称,老 import 不受影响。
- """
- from __future__ import absolute_import
- import re
- import calendar
- from datetime import datetime
- from BiddingKG.dl.common.Utils import isValidDate
- __all__ = [
- "turnMoneySource",
- "get_days_between",
- "extract_serviceTime",
- ]
- def turnMoneySource(moneysource):
- result_list = []
- if re.search("自筹|业主筹集|筹资|自有", moneysource):
- result_list.append("自筹")
- if re.search("财政", moneysource) and not re.search("非财政", moneysource):
- result_list.append("财政资金")
- if re.search("拨款|补助|划拨|拨付|国拨|上级资金", moneysource):
- result_list.append("上级拨款")
- if re.search("社会资本|社会资金", moneysource):
- result_list.append("社会资本")
- if re.search("贷款|借款|借贷", moneysource):
- result_list.append("贷款资金")
- if re.search("债券|债|国债", moneysource):
- result_list.append("债券资金")
- if re.search("专项|项目资金", moneysource):
- result_list.append("项目专项资金")
- if re.search("配套", moneysource):
- result_list.append("配套资金")
- if re.search("外资", moneysource):
- result_list.append("外资")
- if re.search("国有资金|国企资金|国资|国家投资", moneysource):
- result_list.append("国有资金")
- if re.search("投资|融资", moneysource):
- result_list.append("投资资金")
- if re.search("预算(?<!外)|预算内", moneysource):
- result_list.append("预算内资金")
- if re.search("预算外", moneysource):
- result_list.append("预算外资金")
- result_list = sorted(result_list, key=lambda x: x)
- if len(result_list) > 0 and len(result_list) < 5:
- return ",".join(result_list)
- else:
- return "其他资金"
- def get_days_between(day1, day2, get_abs=0):
- '''
- :param day1: 较小日期
- :param day2: 较大日期
- :param get_abs: 是否取绝对值
- :return: 天数差
- '''
- # 将日期字符串转换为datetime对象
- date1 = datetime.strptime(day1, '%Y-%m-%d')
- date2 = datetime.strptime(day2, '%Y-%m-%d')
- # 计算日期差
- delta = date2 - date1
- # 获取天数差
- days_difference = delta.days
- if get_abs:
- return abs(days_difference)
- else:
- return days_difference
- def extract_serviceTime(service_time, page_time):
- pattern1 = re.compile("\d{4}[年\-./]\d{1,2}[月\-./]\d{1,2}日?")
- pattern2 = re.compile("\d+(?:\.\d+)?[((]?个?[^\d]?[^\d]?(?:日|天|周年|整年|学?年|月|周|日历[天日]|工作[天日])")
- pattern3 = re.compile("\d{4}[年\-./]\d{1,2}月?")
- pattern4 = re.compile("(?:日|天|周年|年|月|周|日历[天日]|工作[天日]|星期)[^\d]{1,3}\d+(?:\.\d+)?")
- DigitsDic = {"零": 0, "壹": 1, "贰": 2, "叁": 3, "肆": 4, "伍": 5, "陆": 6, "柒": 7, "捌": 8, "玖": 9,
- "〇": 0, "一": 1, "二": 2, "三": 3, "四": 4, "五": 5, "六": 6, "七": 7, "八": 8, "九": 9,
- "两": 2, '貮': 2}
- def get_month_days(year, month):
- # calendar.monthrange(year, month)返回一个元组,其中第一个元素是月份的第一天是星期几(0-6为星期一到星期日),
- # 第二个元素是该月的天数。
- _, last_day = calendar.monthrange(year, month)
- return last_day
- def get_num(text):
- CN_UNIT = {'十': 10, '拾': 10, '百': 100,
- '佰': 100, '千': 1000, '仟': 1000}
- regex = re.compile(r'[〇一二三四五六七八九零壹贰叁肆伍陆柒捌玖貮两十拾百佰千仟]+')
- text = regex.search(text)
- if text:
- text = text.group()
- else:
- return ""
- result = 0
- result_list = []
- unit = 0
- control = 0
- for i, d in enumerate(text):
- if d in '零百佰千仟' and i == 0:
- return ""
- if d in DigitsDic:
- result += DigitsDic[d]
- elif d in CN_UNIT:
- if unit == 0:
- unit_1 = CN_UNIT[d]
- # 这里的处理主要是考虑到类似于二十三亿五千万这种数
- if result == 0:
- result = CN_UNIT[d]
- else:
- result *= CN_UNIT[d]
- unit = CN_UNIT[d]
- result_1 = result
- elif unit > CN_UNIT[d]:
- result -= DigitsDic[text[i - 1]]
- result += DigitsDic[text[i - 1]] * CN_UNIT[d]
- unit = CN_UNIT[d]
- elif unit <= CN_UNIT[d]:
- if (CN_UNIT[d] < unit_1) and (len(result_list) == control):
- result_list.append(result_1)
- result = (result - result_1) * CN_UNIT[d]
- control += 1
- else:
- result *= CN_UNIT[d]
- unit = CN_UNIT[d]
- if len(result_list) == control:
- unit_1 = unit
- result_1 = result
- else:
- return ""
- return sum(result_list) + result
- serviceTime_dict = {"service_start": "", "service_end": "", "service_days": 0}
- re_num = re.findall(r'[〇一二三四五六七八九零壹贰叁肆伍陆柒捌玖貮两十拾百佰千仟]+', service_time)
- for _num in re_num:
- if not re.search("[十拾百佰千仟]", _num):
- num = ""
- for word in _num:
- num += str(DigitsDic.get(word, word))
- service_time = service_time.replace(_num, num, 1)
- else:
- num = str(get_num(_num))
- service_time = service_time.replace(_num, num, 1)
- end_time = ""
- service_days = 0
- re_page_time = re.search("20\d{2}-\d{2}-\d{2}", page_time)
- page_time = re_page_time.group() if re_page_time else "2000-01-01" # page_time为空时默认值为2000-01-01
- if re.search(pattern1, service_time):
- # end_time = re.findall(pattern1,service_time)[-1]
- time_list = []
- for _time in re.findall(pattern1, service_time):
- _time = re.sub("日", "", _time)
- _time = re.sub("[年月./]", "-", _time)
- _year, _month, _day = _time.split("-")
- _month = int(_month)
- _day = int(_day)
- _year = int(_year)
- if _year > 2050 or _year <= 2000 or _month > 12 or _month <= 0 or _day <= 0 or _day > 31:
- service_days = 0
- else:
- if isValidDate(_year, _month, _day):
- _time = str(_year) + '-' + str(_month) + '-' + str(_day)
- _time = _time.split("-")[0] + '-' + _time.split("-")[1].rjust(2, "0") + '-' + _time.split("-")[
- 2].rjust(2, "0")
- time_list.append(_time)
- if len(time_list) >= 2:
- if get_days_between(page_time, time_list[1]) > 1 and get_days_between(time_list[0], time_list[1]) > 0:
- serviceTime_dict['service_end'] = time_list[1]
- serviceTime_dict['service_start'] = time_list[0]
- elif len(time_list) == 1:
- if get_days_between(page_time, time_list[0]) > 1:
- serviceTime_dict['service_end'] = time_list[0]
- # service_days = (time.mktime(time.strptime(end_time,"%Y-%m-%d"))-page_timestamp)/(24*60*60)
- elif re.search(pattern3, service_time):
- time_list = []
- # end_time = re.findall(pattern3,service_time)[-1]
- for _time in re.findall(pattern3, service_time):
- _time = re.sub("月", "", _time)
- _time = re.sub("[年./]", "-", _time)
- _year, _month = _time.split("-")
- _day = 0
- _month = int(_month)
- _year = int(_year)
- if _year > 2050 or _year <= 2000 or _month > 12 or _month <= 0:
- service_days = 0
- else:
- _day = get_month_days(_year, _month)
- if isValidDate(_year, _month, _day):
- _time = str(_year) + '-' + str(_month) + '-' + str(_day)
- _time = _time.split("-")[0] + '-' + _time.split("-")[1].rjust(2, "0") + '-' + _time.split("-")[
- 2].rjust(2, "0")
- time_list.append(_time)
- if len(time_list) >= 2:
- if get_days_between(page_time, time_list[1]) > 1 and get_days_between(time_list[0], time_list[1]) > 0:
- serviceTime_dict['service_end'] = time_list[1]
- serviceTime_dict['service_start'] = time_list[0]
- elif len(time_list) == 1:
- if get_days_between(page_time, time_list[0]) > 1:
- serviceTime_dict['service_end'] = time_list[0]
- # service_days = (time.mktime(time.strptime(end_time,"%Y-%m-%d"))-page_timestamp)/(24*60*60)
- elif re.search(pattern2, service_time) or re.search(pattern4, service_time):
- for pattern in [pattern2, pattern4]:
- unit = 1
- match = re.findall(pattern, service_time)
- if len(set(match)) == 1:
- match_text = match[0]
- if "月" in match_text:
- unit = 30
- elif "年" in match_text:
- unit = 365
- elif "周" in match_text or "星期" in match_text:
- unit = 7
- match_num = float(re.search("\d+", match_text).group())
- # 数字能被365整除,单位更正为天
- if int(match_num) % 365 == 0:
- unit = 1
- if unit == 365:
- if match_num > 10: # 单位为'年'时,排除数字过大的
- match_num = 0
- elif unit == 30:
- if match_num > 60: # 单位为'月'时,排除数字过大的
- match_num = 0
- elif unit == 1:
- if match_num > 4000: # 单位为'日'时,排除数字过大的
- match_num = 0
- service_days = int(match_num * unit)
- if service_days % 360 == 0:
- service_days = service_days / 360 * 365
- elif service_days % 180 == 0 and service_days % 360 != 0:
- service_days = service_days // 360 * 365 + 180
- service_days = int(service_days)
- if service_days <= 1 and service_days > 4000:
- service_days = 0
- # if service_days>3:
- if service_days > 0:
- # service_days = str(service_days) + "天"
- serviceTime_dict['service_days'] = service_days
- break
- elif "半年" in service_time:
- service_days = 180
- # service_days = str(service_days) + "天"
- serviceTime_dict['service_days'] = service_days
- if serviceTime_dict['service_start'] and serviceTime_dict['service_end']:
- service_days = get_days_between(serviceTime_dict['service_start'], serviceTime_dict['service_end'])
- serviceTime_dict['service_days'] = service_days
- return serviceTime_dict
|