#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2017/11/20 16:39
# @Author  : zhm
# @File    : TimeNormalizer.py
# @Software: PyCharm
# @Changed : QixinLi

import pickle
import regex as re
import arrow
import json
import os

from StringPreHandler import StringPreHandler
from TimePoint import TimePoint
from TimeUnit import TimeUnit

# 时间表达式识别的主要工作类
class TimeNormalizer:
    def __init__(self, isPreferFuture=True):
        self.isPreferFuture = isPreferFuture
        self.pattern, self.holi_solar, self.holi_lunar = self.init()
        self.wordNeed2beChanged = []

    # 这里对一些不规范的表达做转换
    def _filter(self, input_query):
        # 这里对于下个周末这种做转化 把个给移除掉
        input_query = StringPreHandler.numberTranslator(input_query)

        rule = u"[0-9]月[0-9]"
        pattern = re.compile(rule)
        match = pattern.search(input_query)
        if match != None:
            index = input_query.find('月')
            rule = u"日|号"
            pattern = re.compile(rule)
            match = pattern.search(input_query[index:])
            if match == None:
                rule = u"[0-9]月[0-9]+"
                pattern = re.compile(rule)
                match = pattern.search(input_query)
                if match != None:
                    end = match.span()[1]
                    input_query = input_query[:end] + '号' + input_query[end:]

        rule = u"月"
        pattern = re.compile(rule)
        match = pattern.search(input_query)
        if match == None:
            input_query = input_query.replace('个', '')

        input_query = input_query.replace('中旬', '15号')
        input_query = input_query.replace('傍晚', '午后')
        input_query = input_query.replace('大年', '')
        input_query = input_query.replace('五一', '劳动节')
        input_query = input_query.replace('白天', '早上')
        input_query = input_query.replace('：', ':')
        return input_query

    def init(self):
        # fpath = os.path.dirname(__file__) + '/resource/reg.pkl'
        # try:
        #     with open(fpath, 'rb') as f:
        #         pattern = pickle.load(f)
        # except:
        #     with open(os.path.dirname(__file__) + '/resource/regex.txt', 'r', encoding="utf-8") as f:
        #         content = f.read()
        #     p = re.compile(content)
        #     with open(fpath, 'wb') as f:
        #         pickle.dump(p, f)
        #     with open(fpath, 'rb') as f:
        #         pattern = pickle.load(f)
        # with open(os.path.dirname(__file__) + '/resource/holi_solar.json', 'r', encoding='utf-8') as f:
        #     holi_solar = json.load(f)
        # with open(os.path.dirname(__file__) + '/resource/holi_lunar.json', 'r', encoding='utf-8') as f:
        #     holi_lunar = json.load(f)
        pattern = "((前|昨|今|明|后)(天|日)?(早|晚)(晨|上|间)?)|(\d+个?[年月日天][以之]?[前后])|(\d+个?半?(小时|钟头|h|H))|(半个?(小时|钟头))|(\d+(分钟|min))|([13]刻钟)|((上|这|本|下)+(周|星期)([一二三四五六七天日]|[1-7])?)|((周|星期)([一二三四五六七天日]|[1-7]))|((早|晚)?([0-2]?[0-9](点|时)半)(am|AM|pm|PM)?)|((早|晚)?(\d+[:：]\d+([:：]\d+)*)\s*(am|AM|pm|PM)?)|((早|晚)?([0-2]?[0-9](点|时)[13一三]刻)(am|AM|pm|PM)?)|((早|晚)?(\d+[时点](\d+)?分?(\d+秒?)?)\s*(am|AM|pm|PM)?)|(大+(前|后)天)|(([零一二三四五六七八九十百千万]+|\d+)世)|([0-9]?[0-9]?[0-9]{2}\.((10)|(11)|(12)|([1-9]))\.((?<!\\d))([0-3][0-9]|[1-9]))|(现在)|(届时)|(这个月)|((数|多|多少|好几|几|差不多|近|前|后|上|左右)日)|(晚些时候)|(今年)|(长期)|(以前)|(过去)|(时期)|(时代)|(当时)|(近来)|(([零一二三四五六七八九十百千万]+|\d+)夜)|(当前)|(日(数|多|多少|好几|几|差不多|近|前|后|上|左右))|((\d+)点)|(今年([零一二三四五六七八九十百千万]+|\d+))|(\d+[:：]\d+(分|))|((\d+):(\d+))|(\d+/\d+/\d+)|(未来)|((充满美丽、希望、挑战的)?未来)|(最近)|(早上)|(早(数|多|多少|好几|几|差不多|近|前|后|上|左右))|(日前)|(新世纪)|(小时)|(([0-3][0-9]|[1-9])(日|号))|(明天)|(([0-3][0-9]|[1-9])[日号])|((数|多|多少|好几|几|差不多|近|前|后|上|左右)周)|((数|多|多少|好几|几|差不多|近|前|后|上|左右)([零一二三四五六七八九十百千万]+|\d+)年)|([一二三四五六七八九十百千万几多]+[天日周月年][后前左右]*)|(每[年月日天小时分秒钟]+)|((\d+分)+(\d+秒)?)|([一二三四五六七八九十]+来?[岁年])|([新?|\d*]世纪末?)|((\d+)时)|(世纪)|(([零一二三四五六七八九十百千万]+|\d+)岁)|(今年)|([星期周]+[一二三四五六七])|(星期([零一二三四五六七八九十百千万]+|\d+))|(([零一二三四五六七八九十百千万]+|\d+)年)|([本后昨当新后明今去前那这][一二三四五六七八九十]?[年月日天])|(早|早晨|早上|上午|中午|午后|下午|晚上|晚间|夜里|夜|凌晨|深夜)|(回归前后)|((\d+点)+(\d+分)?(\d+秒)?左右?)|((\d+)年代)|(本月(\d+))|(第(\d+)天)|((\d+)岁)|((\d+)年(\d+)月)|([去今明]?[年月](底|末))|(([零一二三四五六七八九十百千万]+|\d+)世纪)|(昨天(数|多|多少|好几|几|差不多|近|前|后|上|左右)午)|(年度)|((数|多|多少|好几|几|差不多|近|前|后|上|左右)星期)|(年底)|([下个本]+赛季)|(今年(\d+)月(\d+)日)|((\d+)月(\d+)日(数|多|多少|好几|几|差不多|近|前|后|上|左右)午(\d+)时)|(今年晚些时候)|(两个星期)|(过去(数|多|多少|好几|几|差不多|近|前|后|上|左右)周)|(本赛季)|(半个(数|多|多少|好几|几|差不多|近|前|后|上|左右))|(稍晚)|((\d+)号晚(数|多|多少|好几|几|差不多|近|前|后|上|左右))|(今(数|多|多少|好几|几|差不多|近|前|后|上|左右)(\d+)年)|(这个时候)|((数|多|多少|好几|几|差不多|近|前|后|上|左右)个小时)|(最(数|多|多少|好几|几|差不多|近|前|后|上|左右)(数|多|多少|好几|几|差不多|近|前|后|上|左右)年)|(凌晨)|((\d+)年(\d+)月(\d+)日)|((\d+)个月)|(今天早(数|多|多少|好几|几|差不多|近|前|后|上|左右))|(第[一二三四五六七八九十\d+]+季)|(当地时间)|(今(数|多|多少|好几|几|差不多|近|前|后|上|左右)([零一二三四五六七八九十百千万]+|\d+)年)|(早晨)|(一段时间)|([本上]周[一二三四五六七])|(凌晨(\d+)点)|(去年(\d+)月(\d+)日)|(年关)|(如今)|((数|多|多少|好几|几|差不多|近|前|后|上|左右)小时)|(当晚)|((\d+)日晚(\d+)时)|(([零一二三四五六七八九十百千万]+|\d+)(数|多|多少|好几|几|差不多|近|前|后|上|左右)午)|(每年(\d+)月(\d+)日)|(([零一二三四五六七八九十百千万]+|\d+)周)|((\d+)月)|(农历)|(两个小时)|(本周([零一二三四五六七八九十百千万]+|\d+))|(长久)|(清晨)|((\d+)号晚)|(春节)|(星期日)|(圣诞)|((数|多|多少|好几|几|差不多|近|前|后|上|左右)段)|(现年)|(当日)|((数|多|多少|好几|几|差不多|近|前|后|上|左右)分钟)|(\d+(天|日|周|月|年)(后|前|))|((文艺复兴|巴洛克|前苏联|前一|暴力和专制|成年时期|古罗马|我们所处的敏感)+时期)|((\d+)[年月天])|(清早)|(两年)|((数|多|多少|好几|几|差不多|近|前|后|上|左右)午)|(昨天(数|多|多少|好几|几|差不多|近|前|后|上|左右)午(\d+)时)|(([零一二三四五六七八九十百千万]+|\d+)(数|多|多少|好几|几|差不多|近|前|后|上|左右)年)|(今(数|多|多少|好几|几|差不多|近|前|后|上|左右)(\d+))|(圣诞节)|(学期)|(\d+来?分钟)|(过去(数|多|多少|好几|几|差不多|近|前|后|上|左右)年)|(星期天)|(夜间)|((\d+)日凌晨)|(([零一二三四五六七八九十百千万]+|\d+)月底)|(当天)|((\d+)日)|(((10)|(11)|(12)|([1-9]))月)|((数|多|多少|好几|几|差不多|近|前|后|上|左右)(数|多|多少|好几|几|差不多|近|前|后|上|左右)年)|(今年(\d+)月份)|(晚(数|多|多少|好几|几|差不多|近|前|后|上|左右)(\d+)时)|(连[年月日夜])|((\d+)年(\d+)月(\d+)日(数|多|多少|好几|几|差不多|近|前|后|上|左右)午)|((一|二|两|三|四|五|六|七|八|九|十|百|千|万|几|多|上|\d+)+个?(天|日|周|月|年)(后|前|半|))|((胜利的)日子)|(青春期)|((数|多|多少|好几|几|差不多|近|前|后|上|左右)年)|(早(数|多|多少|好几|几|差不多|近|前|后|上|左右)([零一二三四五六七八九十百千万]+|\d+)点(数|多|多少|好几|几|差不多|近|前|后|上|左右))|([0-9]{4}年)|(周末)|(([零一二三四五六七八九十百千万]+|\d+)个(数|多|多少|好几|几|差不多|近|前|后|上|左右)小时)|(([(小学)|初中?|高中?|大学?|研][一二三四五六七八九十]?(\d+)?)?[上下]半?学期)|(([零一二三四五六七八九十百千万]+|\d+)时期)|(午间)|(次年)|(这时候)|(农历新年)|([春夏秋冬](天|季))|((\d+)天)|(元宵节)|((数|多|多少|好几|几|差不多|近|前|后|上|左右)分)|((\d+)月(\d+)日(数|多|多少|好几|几|差不多|近|前|后|上|左右)午)|(晚(数|多|多少|好几|几|差不多|近|前|后|上|左右)(\d+)时(\d+)分)|(傍晚)|(周([零一二三四五六七八九十百千万]+|\d+))|((数|多|多少|好几|几|差不多|近|前|后|上|左右)午(\d+)时(\d+)分)|(同日)|((\d+)年(\d+)月底)|((\d+)分钟)|((\d+)世纪)|(冬季)|(清明)(节)?|(立春)|(雨水)|(惊蛰)|(春分)|(谷雨)|(立夏)|(小满 )|(芒种)|(夏至)|(小暑)|(大暑)|(立秋)|(处暑)|(白露)|(秋分)|(寒露)|(霜降)|(立冬)|(小雪)|(大雪)|(冬至)|(小寒)|(大寒)|(青年节)|(教师节)|(中元节)|(端午)(节)?|(劳动节)|(7夕)(节)?|(建党节)|(建军节)|(初13)|(初14)|(初15)|(初12)|(初11)|(初9)|(初8)|(初7)|(初6)|(初5)|(初4)|(初3)|(初2)|(初1)|(情人节)|(母亲节)|(中和节)|(圣诞)(节)?|(中秋)(节)?|(春节)|(元宵)(节)?|(航海日)|(儿童节)|(国庆)(节)?|(植树节)|(元旦)|(重阳节)|(妇女节)|(记者节)|(年代)|(([零一二三四五六七八九十百千万]+|\d+)年半)|(今年年底)|(新年)|(本周)|(当地时间星期([零一二三四五六七八九十百千万]+|\d+))|(([零一二三四五六七八九十百千万]+|\d+)(数|多|多少|好几|几|差不多|近|前|后|上|左右)岁)|(半小时)|(每周)|(([零一二三四五六七八九十百千万]+|\d+)周年)|((重要|最后)?时刻)|(([零一二三四五六七八九十百千万]+|\d+)期间)|(周日)|(晚(数|多|多少|好几|几|差不多|近|前|后|上|左右))|(今后)|(([零一二三四五六七八九十百千万]+|\d+)段时间)|(明年)|([12][09][0-9]{2}(年度?((前|昨|今|明|后)(天|日)?(早|晚)(晨|上|间)?)|(\d+个?[年月日天][以之]?[前后])|(\d+个?半?(小时|钟头|h|H))|(半个?(小时|钟头))|(\d+(分钟|min))|([13]刻钟)|((上|这|本|下)+(周|星期)([一二三四五六七天日]|[1-7])?)|((周|星期)([一二三四五六七天日]|[1-7]))|((早|晚)?([0-2]?[0-9](点|时)半)(am|AM|pm|PM)?)|((早|晚)?(\d+[:：]\d+([:：]\d+)*)\s*(am|AM|pm|PM)?)|((早|晚)?([0-2]?[0-9](点|时)[13一三]刻)(am|AM|pm|PM)?)|((早|晚)?(\d+[时点](\d+)?分?(\d+秒?)?)\s*(am|AM|pm|PM)?)|(大+(前|后)天)|(([零一二三四五六七八九十百千万]+|\d+)世)|([0-9]?[0-9]?[0-9]{2}\.((10)|(11)|(12)|([1-9]))\.((?<!\d))([0-3][0-9]|[1-9]))|(现在)|(届时)|(这个月)|((数|多|多少|好几|几|差不多|近|前|后|上|左右)日)|(晚些时候)|(今年)|(长期)|(以前)|(过去)|(时期)|(时代)|(当时)|(近来)|(([零一二三四五六七八九十百千万]+|\d+)夜)|(当前)|(日(数|多|多少|好几|几|差不多|近|前|后|上|左右))|((\d+)点)|(今年([零一二三四五六七八九十百千万]+|\d+))|(\d+[:：]\d+(分|))|((\d+):(\d+))|(\d+/\d+/\d+)|(未来)|((充满美丽、希望、挑战的)?未来)|(最近)|(早上)|(早(数|多|多少|好几|几|差不多|近|前|后|上|左右))|(日前)|(新世纪)|(小时)|(([0-3][0-9]|[1-9])(日|号))|(明天)|(\d+)月|(([0-3][0-9]|[1-9])[日号])|((数|多|多少|好几|几|差不多|近|前|后|上|左右)周)|((数|多|多少|好几|几|差不多|近|前|后|上|左右)([零一二三四五六七八九十百千万]+|\d+)年)|([一二三四五六七八九十百千万几多]+[天日周月年][后前左右]*)|(每[年月日天小时分秒钟]+)|((\d+分)+(\d+秒)?)|([一二三四五六七八九十]+来?[岁年])|([新?|\d*]世纪末?)|((\d+)时)|(世纪)|(([零一二三四五六七八九十百千万]+|\d+)岁)|(今年)|([星期周]+[一二三四五六七])|(星期([零一二三四五六七八九十百千万]+|\d+))|(([零一二三四五六七八九十百千万]+|\d+)年)|([本后昨当新后明今去前那这][一二三四五六七八九十]?[年月日天])|(早|早晨|早上|上午|中午|午后|下午|晚上|晚间|夜里|夜|凌晨|深夜)|(回归前后)|((\d+点)+(\d+分)?(\d+秒)?左右?)|((\d+)年代)|(本月(\d+))|(第(\d+)天)|((\d+)岁)|((\d+)年(\d+)月)|([去今明]?[年月](底|末))|(([零一二三四五六七八九十百千万]+|\d+)世纪)|(昨天(数|多|多少|好几|几|差不多|近|前|后|上|左右)午)|(年度)|((数|多|多少|好几|几|差不多|近|前|后|上|左右)星期)|(年底)|([下个本]+赛季)|(\d+)月(\d+)日|(\d+)月(\d+)|(今年(\d+)月(\d+)日)|((\d+)月(\d+)日(数|多|多少|好几|几|差不多|近|前|后|上|左右)午(\d+)时)|(今年晚些时候)|(两个星期)|(过去(数|多|多少|好几|几|差不多|近|前|后|上|左右)周)|(本赛季)|(半个(数|多|多少|好几|几|差不多|近|前|后|上|左右))|(稍晚)|((\d+)号晚(数|多|多少|好几|几|差不多|近|前|后|上|左右))|(今(数|多|多少|好几|几|差不多|近|前|后|上|左右)(\d+)年)|(这个时候)|((数|多|多少|好几|几|差不多|近|前|后|上|左右)个小时)|(最(数|多|多少|好几|几|差不多|近|前|后|上|左右)(数|多|多少|好几|几|差不多|近|前|后|上|左右)年)|(凌晨)|((\d+)年(\d+)月(\d+)日)|((\d+)个月)|(今天早(数|多|多少|好几|几|差不多|近|前|后|上|左右))|(第[一二三四五六七八九十\d+]+季)|(当地时间)|(今(数|多|多少|好几|几|差不多|近|前|后|上|左右)([零一二三四五六七八九十百千万]+|\d+)年)|(早晨)|(一段时间)|([本上]周[一二三四五六七])|(凌晨(\d+)点)|(去年(\d+)月(\d+)日)|(年关)|(如今)|((数|多|多少|好几|几|差不多|近|前|后|上|左右)小时)|(当晚)|((\d+)日晚(\d+)时)|(([零一二三四五六七八九十百千万]+|\d+)(数|多|多少|好几|几|差不多|近|前|后|上|左右)午)|(每年(\d+)月(\d+)日)|(([零一二三四五六七八九十百千万]+|\d+)周)|((\d+)月)|(农历)|(两个小时)|(本周([零一二三四五六七八九十百千万]+|\d+))|(长久)|(清晨)|((\d+)号晚)|(春节)|(星期日)|(圣诞)|((数|多|多少|好几|几|差不多|近|前|后|上|左右)段)|(现年)|(当日)|((数|多|多少|好几|几|差不多|近|前|后|上|左右)分钟)|(\d+(天|日|周|月|年)(后|前|))|((文艺复兴|巴洛克|前苏联|前一|暴力和专制|成年时期|古罗马|我们所处的敏感)+时期)|((\d+)[年月天])|(清早)|(两年)|((数|多|多少|好几|几|差不多|近|前|后|上|左右)午)|(昨天(数|多|多少|好几|几|差不多|近|前|后|上|左右)午(\d+)时)|(([零一二三四五六七八九十百千万]+|\d+)(数|多|多少|好几|几|差不多|近|前|后|上|左右)年)|(今(数|多|多少|好几|几|差不多|近|前|后|上|左右)(\d+))|(圣诞节)|(学期)|(\d+来?分钟)|(过去(数|多|多少|好几|几|差不多|近|前|后|上|左右)年)|(星期天)|(夜间)|((\d+)日凌晨)|(([零一二三四五六七八九十百千万]+|\d+)月底)|(当天)|((\d+)日)|(((10)|(11)|(12)|([1-9]))月)|((数|多|多少|好几|几|差不多|近|前|后|上|左右)(数|多|多少|好几|几|差不多|近|前|后|上|左右)年)|(今年(\d+)月份)|(晚(数|多|多少|好几|几|差不多|近|前|后|上|左右)(\d+)时)|(连[年月日夜])|((\d+)年(\d+)月(\d+)日(数|多|多少|好几|几|差不多|近|前|后|上|左右)午)|((一|二|两|三|四|五|六|七|八|九|十|百|千|万|几|多|上|\d+)+个?(天|日|周|月|年)(后|前|半|))|((胜利的)日子)|(青春期)|((数|多|多少|好几|几|差不多|近|前|后|上|左右)年)|(早(数|多|多少|好几|几|差不多|近|前|后|上|左右)([零一二三四五六七八九十百千万]+|\d+)点(数|多|多少|好几|几|差不多|近|前|后|上|左右))|([0-9]{4}年)|(周末)|(([零一二三四五六七八九十百千万]+|\d+)个(数|多|多少|好几|几|差不多|近|前|后|上|左右)小时)|(([(小学)|初中?|高中?|大学?|研][一二三四五六七八九十]?(\d+)?)?[上下]半?学期)|(([零一二三四五六七八九十百千万]+|\d+)时期)|(午间)|(次年)|(这时候)|(农历新年)|([春夏秋冬](天|季))|((\d+)天)|(元宵节)|((数|多|多少|好几|几|差不多|近|前|后|上|左右)分)|((\d+)月(\d+)日(数|多|多少|好几|几|差不多|近|前|后|上|左右)午)|(晚(数|多|多少|好几|几|差不多|近|前|后|上|左右)(\d+)时(\d+)分)|(傍晚)|(周([零一二三四五六七八九十百千万]+|\d+))|((数|多|多少|好几|几|差不多|近|前|后|上|左右)午(\d+)时(\d+)分)|(同日)|((\d+)年(\d+)月底)|((\d+)分钟)|((\d+)世纪)|(冬季)|(年代)|(([零一二三四五六七八九十百千万]+|\d+)年半)|(今年年底)|(新年)|(本周)|(当地时间星期([零一二三四五六七八九十百千万]+|\d+))|(([零一二三四五六七八九十百千万]+|\d+)(数|多|多少|好几|几|差不多|近|前|后|上|左右)岁)|(半小时)|(每周)|(([零一二三四五六七八九十百千万]+|\d+)周年)|((重要|最后)?时刻)|(([零一二三四五六七八九十百千万]+|\d+)期间)|(周日)|(晚(数|多|多少|好几|几|差不多|近|前|后|上|左右))|(今后)|(([零一二三四五六七八九十百千万]+|\d+)段时间)|(明年)|([12][09][0-9]{2}(年度?))|(([零一二三四五六七八九十百千万]+|\d+)生)|(今天凌晨)|(过去(\d+)年)|(元月)|((\d+)月(\d+)日凌晨)|([前去今明后新]+年)|((\d+)月(\d+))|(夏天)|((\d+)日凌晨(\d+)时许)|((\d+)月(\d+)日)|((\d+)点半)|(去年底)|(最后一[天刻])|(最(数|多|多少|好几|几|差不多|近|前|后|上|左右)(数|多|多少|好几|几|差不多|近|前|后|上|左右)个月)|(圣诞节?)|(下?个?(星期|周)(一|二|三|四|五|六|七|天))|((\d+)(数|多|多少|好几|几|差不多|近|前|后|上|左右)年)|(当天(数|多|多少|好几|几|差不多|近|前|后|上|左右)午)|(每年的(\d+)月(\d+)日)|((\d+)日晚(数|多|多少|好几|几|差不多|近|前|后|上|左右))|(星期([零一二三四五六七八九十百千万]+|\d+)晚)|(深夜)|(现如今)|([上中下]+午)|(第(一|二|三|四|五|六|七|八|九|十|百|千|万|几|多|\d+)+个?(天|日|周|月|年))|(昨晚)|(近年)|(今天清晨)|(中旬)|(星期([零一二三四五六七八九十百千万]+|\d+)早)|(([零一二三四五六七八九十百千万]+|\d+)战期间)|(星期)|(昨天晚(数|多|多少|好几|几|差不多|近|前|后|上|左右))|(较早时)|(个(数|多|多少|好几|几|差不多|近|前|后|上|左右)小时)|((民主高中|我们所处的|复仇主义和其它危害人类的灾难性疾病盛行的|快速承包电影主权的|恢复自我美德|人类审美力基础设施|饱受暴力、野蛮、流血、仇恨、嫉妒的|童年|艰苦的童年)+时代)|(元旦)|(([零一二三四五六七八九十百千万]+|\d+)个礼拜)|(昨日)|([年月]初)|((\d+)年的(\d+)月)|(每年)|(([零一二三四五六七八九十百千万]+|\d+)月份)|(今年(\d+)月(\d+)号)|(今年([零一二三四五六七八九十百千万]+|\d+)月)|((\d+)月底)|(未来(\d+)年)|(第([零一二三四五六七八九十百千万]+|\d+)季)|(\d?多年)|(([零一二三四五六七八九十百千万]+|\d+)个星期)|((\d+)年([零一二三四五六七八九十百千万]+|\d+)月)|([下上中]午)|(早(数|多|多少|好几|几|差不多|近|前|后|上|左右)(\d+)点)|((数|多|多少|好几|几|差不多|近|前|后|上|左右)月)|(([零一二三四五六七八九十百千万]+|\d+)个(数|多|多少|好几|几|差不多|近|前|后|上|左右)月)|(同([零一二三四五六七八九十百千万]+|\d+)天)|((\d+)号凌晨)|(夜里)|(两个(数|多|多少|好几|几|差不多|近|前|后|上|左右)小时)|(昨天)|(罗马时代)|(目(数|多|多少|好几|几|差不多|近|前|后|上|左右))|(([零一二三四五六七八九十百千万]+|\d+)月)|((\d+)年(\d+)月(\d+)号)|(((10)|(11)|(12)|([1-9]))月份?)|([12][0-9]世纪)|((数|多|多少|好几|几|差不多|近|前|后|上|左右)([零一二三四五六七八九十百千万]+|\d+)天)|(工作日)|(稍后)|((\d+)号(数|多|多少|好几|几|差不多|近|前|后|上|左右)午)|(未来([零一二三四五六七八九十百千万]+|\d+)年)|([0-9]+[天日周月年][后前左右]*)|(([零一二三四五六七八九十百千万]+|\d+)日(数|多|多少|好几|几|差不多|近|前|后|上|左右)午)|(最(数|多|多少|好几|几|差不多|近|前|后|上|左右)([零一二三四五六七八九十百千万]+|\d+)刻)|(很久)|((\d+)(数|多|多少|好几|几|差不多|近|前|后|上|左右)岁)|(去年(\d+)月(\d+)号)|(两个月)|((数|多|多少|好几|几|差不多|近|前|后|上|左右)午(\d+)时)|(古代)|(两天)|(\d+个?(小时|星期))|((\d+)年半)|(较早)|(([零一二三四五六七八九十百千万]+|\d+)个小时)|([一二三四五六七八九十]+周年)|(星期([零一二三四五六七八九十百千万]+|\d+)(数|多|多少|好几|几|差不多|近|前|后|上|左右)午)|(时刻)|((\d+天)+(\d+点)?(\d+分)?(\d+秒)?)|((\d+)日([零一二三四五六七八九十百千万]+|\d+)时)|((\d+)周年)|(([零一二三四五六七八九十百千万]+|\d+)早)|(([零一二三四五六七八九十百千万]+|\d+)日)|(去年(\d+)月)|(过去([零一二三四五六七八九十百千万]+|\d+)年)|((\d+)个星期)|((数|多|多少|好几|几|差不多|近|前|后|上|左右)(数|多|多少|好几|几|差不多|近|前|后|上|左右)天)|(执政期间)|([当前昨今明后春夏秋冬]+天)|(去年(\d+)月份)|(今(数|多|多少|好几|几|差不多|近|前|后|上|左右))|((\d+)周)|(两星期)|(([零一二三四五六七八九十百千万]+|\d+)年代)|((数|多|多少|好几|几|差不多|近|前|后|上|左右)天)|(昔日)|(两个半月)|([印尼|北京|美国]?当地时间)|(连日)|(本月(\d+)日)|(第([零一二三四五六七八九十百千万]+|\d+)天)|((\d+)点(\d+)分)|([长近多]年)|((\d+)日(数|多|多少|好几|几|差不多|近|前|后|上|左右)午(\d+)时)|(那时)|(冷战时代)|(([零一二三四五六七八九十百千万]+|\d+)天)|(这个星期)|(去年)|(昨天傍晚)|(近期)|(星期([零一二三四五六七八九十百千万]+|\d+)早些时候)|((\d+)([零一二三四五六七八九十百千万]+|\d+)年)|((数|多|多少|好几|几|差不多|近|前|后|上|左右)两个月)|((\d+)个小时)|(([零一二三四五六七八九十百千万]+|\d+)个月)|(当年)|(本月)|((数|多|多少|好几|几|差不多|近|前|后|上|左右)([零一二三四五六七八九十百千万]+|\d+)个月)|((\d+)点(数|多|多少|好几|几|差不多|近|前|后|上|左右))|(目前)|(去年([零一二三四五六七八九十百千万]+|\d+)月)|((\d+)时(\d+)分)|(每月)|((数|多|多少|好几|几|差不多|近|前|后|上|左右)段时间)|((\d+)日晚)|(早(数|多|多少|好几|几|差不多|近|前|后|上|左右)(\d+)点(数|多|多少|好几|几|差不多|近|前|后|上|左右))|(下旬)|((\d+)月份)|(逐年)|(稍(数|多|多少|好几|几|差不多|近|前|后|上|左右))|((\d+)年)|(月底)|(这个月)|((\d+)年(\d+)个月)|(\d+大寿)|(周([零一二三四五六七八九十百千万]+|\d+)早(数|多|多少|好几|几|差不多|近|前|后|上|左右))|(半年)|(今日)|(末日)|(昨天深夜)|(今年(\d+)月)|((\d+)月(\d+)号)|((\d+)日夜)|((早些|某个|晚间|本星期早些|前些)+时候)|(同年)|((北京|那个|更长的|最终冲突的)时间)|(每个月)|(一早)|((\d+)来?[岁年])|((数|多|多少|好几|几|差不多|近|前|后|上|左右)个月)|([鼠牛虎兔龙蛇马羊猴鸡狗猪]年)|(季度)|(早些时候)|(今天)|(每天)|(年半)|(午后)|((\d+)日(数|多|多少|好几|几|差不多|近|前|后|上|左右)午)|((数|多|多少|好几|几|差不多|近|前|后|上|左右)个星期)|(今天(数|多|多少|好几|几|差不多|近|前|后|上|左右)午)|(同[一二三四五六七八九十][年|月|天])|(T\d+:\d+:\d+)|(\d+/\d+/\d+:\d+:\d+.\d+)|(\?\?\?\?-\?\?-\?\?T\d+:\d+:\d+)|(\d+-\d+-\d+T\d+:\d+:\d+)|(\d+/\d+/\d+ \d+:\d+:\d+.\d+)|(\d+-\d+-\d+|[0-9]{8})|(((\d+)年)?((10)|(11)|(12)|([1-9]))月(\d+))|((\d[\.\-])?((10)|(11)|(12)|([1-9]))[\.\-](\d+))))|(([零一二三四五六七八九十百千万]+|\d+)生)|(今天凌晨)|(过去(\d+)年)|(元月)|((\d+)月(\d+)日凌晨)|([前去今明后新]+年)|((\d+)月(\d+))|(夏天)|((\d+)日凌晨(\d+)时许)|((\d+)月(\d+)日)|((\d+)点半)|(去年底)|(最后一[天刻])|(最(数|多|多少|好几|几|差不多|近|前|后|上|左右)(数|多|多少|好几|几|差不多|近|前|后|上|左右)个月)|(圣诞节?)|(下?个?(星期|周)(一|二|三|四|五|六|七|天))|((\d+)(数|多|多少|好几|几|差不多|近|前|后|上|左右)年)|(当天(数|多|多少|好几|几|差不多|近|前|后|上|左右)午)|(每年的(\d+)月(\d+)日)|((\d+)日晚(数|多|多少|好几|几|差不多|近|前|后|上|左右))|(星期([零一二三四五六七八九十百千万]+|\d+)晚)|(深夜)|(现如今)|([上中下]+午)|(第(一|二|三|四|五|六|七|八|九|十|百|千|万|几|多|\d+)+个?(天|日|周|月|年))|(昨晚)|(近年)|(今天清晨)|(中旬)|(星期([零一二三四五六七八九十百千万]+|\d+)早)|(([零一二三四五六七八九十百千万]+|\d+)战期间)|(星期)|(昨天晚(数|多|多少|好几|几|差不多|近|前|后|上|左右))|(较早时)|(个(数|多|多少|好几|几|差不多|近|前|后|上|左右)小时)|((民主高中|我们所处的|复仇主义和其它危害人类的灾难性疾病盛行的|快速承包电影主权的|恢复自我美德|人类审美力基础设施|饱受暴力、野蛮、流血、仇恨、嫉妒的|童年|艰苦的童年)+时代)|(元旦)|(([零一二三四五六七八九十百千万]+|\d+)个礼拜)|(昨日)|([年月]初)|((\d+)年的(\d+)月)|(每年)|(([零一二三四五六七八九十百千万]+|\d+)月份)|(今年(\d+)月(\d+)号)|(今年([零一二三四五六七八九十百千万]+|\d+)月)|((\d+)月底)|(未来(\d+)年)|(第([零一二三四五六七八九十百千万]+|\d+)季)|(\d?多年)|(([零一二三四五六七八九十百千万]+|\d+)个星期)|((\d+)年([零一二三四五六七八九十百千万]+|\d+)月)|([下上中]午)|(早(数|多|多少|好几|几|差不多|近|前|后|上|左右)(\d+)点)|((数|多|多少|好几|几|差不多|近|前|后|上|左右)月)|(([零一二三四五六七八九十百千万]+|\d+)个(数|多|多少|好几|几|差不多|近|前|后|上|左右)月)|(同([零一二三四五六七八九十百千万]+|\d+)天)|((\d+)号凌晨)|(夜里)|(两个(数|多|多少|好几|几|差不多|近|前|后|上|左右)小时)|(昨天)|(罗马时代)|(目(数|多|多少|好几|几|差不多|近|前|后|上|左右))|(([零一二三四五六七八九十百千万]+|\d+)月)|((\d+)年(\d+)月(\d+)号)|(((10)|(11)|(12)|([1-9]))月份?)|([12][0-9]世纪)|((数|多|多少|好几|几|差不多|近|前|后|上|左右)([零一二三四五六七八九十百千万]+|\d+)天)|(工作日)|(稍后)|((\d+)号(数|多|多少|好几|几|差不多|近|前|后|上|左右)午)|(未来([零一二三四五六七八九十百千万]+|\d+)年)|([0-9]+[天日周月年][后前左右]*)|(([零一二三四五六七八九十百千万]+|\d+)日(数|多|多少|好几|几|差不多|近|前|后|上|左右)午)|(最(数|多|多少|好几|几|差不多|近|前|后|上|左右)([零一二三四五六七八九十百千万]+|\d+)刻)|(很久)|((\d+)(数|多|多少|好几|几|差不多|近|前|后|上|左右)岁)|(去年(\d+)月(\d+)号)|(两个月)|((数|多|多少|好几|几|差不多|近|前|后|上|左右)午(\d+)时)|(古代)|(两天)|(\d+个?(小时|星期))|((\d+)年半)|(较早)|(([零一二三四五六七八九十百千万]+|\d+)个小时)|([一二三四五六七八九十]+周年)|(星期([零一二三四五六七八九十百千万]+|\d+)(数|多|多少|好几|几|差不多|近|前|后|上|左右)午)|(时刻)|((\d+天)+(\d+点)?(\d+分)?(\d+秒)?)|((\d+)日([零一二三四五六七八九十百千万]+|\d+)时)|((\d+)周年)|(([零一二三四五六七八九十百千万]+|\d+)早)|(([零一二三四五六七八九十百千万]+|\d+)日)|(去年(\d+)月)|(过去([零一二三四五六七八九十百千万]+|\d+)年)|((\d+)个星期)|((数|多|多少|好几|几|差不多|近|前|后|上|左右)(数|多|多少|好几|几|差不多|近|前|后|上|左右)天)|(执政期间)|([当前昨今明后春夏秋冬]+天)|(去年(\d+)月份)|(今(数|多|多少|好几|几|差不多|近|前|后|上|左右))|((\d+)周)|(两星期)|(([零一二三四五六七八九十百千万]+|\d+)年代)|((数|多|多少|好几|几|差不多|近|前|后|上|左右)天)|(昔日)|(两个半月)|([印尼|北京|美国]?当地时间)|(连日)|(本月(\d+)日)|(第([零一二三四五六七八九十百千万]+|\d+)天)|((\d+)点(\d+)分)|([长近多]年)|((\d+)日(数|多|多少|好几|几|差不多|近|前|后|上|左右)午(\d+)时)|(那时)|(冷战时代)|(([零一二三四五六七八九十百千万]+|\d+)天)|(这个星期)|(去年)|(昨天傍晚)|(近期)|(星期([零一二三四五六七八九十百千万]+|\d+)早些时候)|((\d+)([零一二三四五六七八九十百千万]+|\d+)年)|((数|多|多少|好几|几|差不多|近|前|后|上|左右)两个月)|((\d+)个小时)|(([零一二三四五六七八九十百千万]+|\d+)个月)|(当年)|(本月)|((数|多|多少|好几|几|差不多|近|前|后|上|左右)([零一二三四五六七八九十百千万]+|\d+)个月)|((\d+)点(数|多|多少|好几|几|差不多|近|前|后|上|左右))|(目前)|(去年([零一二三四五六七八九十百千万]+|\d+)月)|((\d+)时(\d+)分)|(每月)|((数|多|多少|好几|几|差不多|近|前|后|上|左右)段时间)|((\d+)日晚)|(早(数|多|多少|好几|几|差不多|近|前|后|上|左右)(\d+)点(数|多|多少|好几|几|差不多|近|前|后|上|左右))|(下旬)|((\d+)月份)|(逐年)|(稍(数|多|多少|好几|几|差不多|近|前|后|上|左右))|((\d+)年)|(月底)|(这个月)|((\d+)年(\d+)个月)|(\d+大寿)|(周([零一二三四五六七八九十百千万]+|\d+)早(数|多|多少|好几|几|差不多|近|前|后|上|左右))|(半年)|(今日)|(末日)|(昨天深夜)|(今年(\d+)月)|((\d+)月(\d+)号)|((\d+)日夜)|((早些|某个|晚间|本星期早些|前些)+时候)|(同年)|((北京|那个|更长的|最终冲突的)时间)|(每个月)|(一早)|((\d+)来?[岁年])|((数|多|多少|好几|几|差不多|近|前|后|上|左右)个月)|([鼠牛虎兔龙蛇马羊猴鸡狗猪]年)|(季度)|(早些时候)|(今天)|(每天)|(年半)|(下*个?月)|(午后)|((\d+)日(数|多|多少|好几|几|差不多|近|前|后|上|左右)午)|((数|多|多少|好几|几|差不多|近|前|后|上|左右)个星期)|(\d+秒)|(今天(数|多|多少|好几|几|差不多|近|前|后|上|左右)午)|(同[一二三四五六七八九十][年|月|天])|(T\d+:\d+:\d+)|(\d+/\d+/\d+:\d+:\d+.\d+)|(\?\?\?\?-\?\?-\?\?T\d+:\d+:\d+)|(\d+-\d+-\d+T\d+:\d+:\d+)|(\d+/\d+/\d+ \d+:\d+:\d+.\d+)|(\d+-\d+-\d+|[0-9]{8})|(((\d+)年)?((10)|(11)|(12)|([1-9]))月(\d+))|((\d[\.\-])?((10)|(11)|(12)|([1-9]))[\.\-](\d+))"
        pattern = re.compile(pattern)
        holi_solar = {
          "植树节": "03-12",
          "圣诞节": "12-25",
          "青年节": "05-04",
          "教师节": "09-10",
          "儿童节": "06-01",
          "元旦节": "01-01",
          "国庆节": "10-01",
          "劳动节": "05-01",
          "妇女节": "03-08",
          "建军节": "08-01",
          "航海日节": "07-11",
          "建党节": "07-01",
          "记者节": "11-08",
          "情人节":"02-14",
          "母亲节":"05-11"
        }
        holi_lunar = {
          "中和节": "02-02",
          "中秋节": "08-15",
          "中元节": "07-15",
          "端午节": "05-05",
          "春节": "01-01",
          "元宵节": "01-15",
          "重阳节": "09-09",
          "7夕节": "07-07",
          "初1节": "01-01",
          "初2节": "01-02",
          "初3节": "01-03",
          "初4节": "01-04",
          "初5节": "01-05",
          "初6节": "01-06",
          "初7节": "01-07",
          "初8节": "01-08",
          "初9节": "01-09",
          "初10节": "01-10",
          "初11节": "01-11",
          "初12节": "01-12",
          "初13节": "01-13",
          "初14节": "01-14",
          "初15节": "01-15"
        }
        return pattern, holi_solar, holi_lunar

    def parse(self, target, timeBase=arrow.now()):
        """
        TimeNormalizer的构造方法，timeBase取默认的系统当前时间
        :param timeBase: 基准时间点
        :param target: 待分析字符串
        :return: 时间单元数组
        """
        self.isTimeSpan = False
        self.invalidSpan = False
        self.timeSpan = ''
        self.target = self._filter(target)
        self.timeBase = arrow.get(timeBase).format('YYYY-M-D-H-m-s')
        self.nowTime = timeBase
        self.oldTimeBase = self.timeBase
        self.__preHandling()
        self.timeToken = self.__timeEx()

        dic = {}
        res = self.timeToken
        dic['word'] = self.wordNeed2beChanged
        if self.isTimeSpan:
            if self.invalidSpan:
                dic['type'] = 'error'
            else:
                result = {}
                dic['type'] = 'timedelta'
                dic['timedelta'] = self.timeSpan
                # print(dic['timedelta'])
                index = dic['timedelta'].find('days')

                days = int(dic['timedelta'][:index-1])
                result['year'] = int(days / 365)
                result['month'] = int(days / 30 - result['year'] * 12)
                result['day'] = int(days - result['year'] * 365 - result['month'] * 30)
                index = dic['timedelta'].find(',')
                time = dic['timedelta'][index+1:]
                time = time.split(':')
                result['hour'] = int(time[0])
                result['minute'] = int(time[1])
                result['second'] = int(time[2])
                dic['timedelta'] = result
        else:
            dic['timebase'] = self.timeBase
            dic['timespan'] = []
            # dic['timestamp'] = [res[0].time.format("YYYY-MM-DD HH:mm:ss")]
            if len(res) == 0:
                dic['type'] = 'error'
            # elif len(res) == 1:
            #     if res[0].time_span:
            #         if isinstance(res[0].time_span, list):
            #             dic['timespan'].append(self.__dist2Span(res[0].time_span,res[0].time))
            #         elif isinstance(res[0].time_span, str):
            #             dic['timespan'].append(self.__str2Span(res[0].time_span,res[0].time))
            #     dic['type'] = 'timestamp'

            else:
                dic['type'] = 'timespan'
                for r in res:
                    if r.time_span:
                        if isinstance(r.time_span, list):
                            dic['timespan'].append(self.__dist2Span(r.time_span, r.time))
                        elif isinstance(r.time_span, str):
                            dic['timespan'].append(self.__str2Span(r.time_span, r.time))
                # dic['timespan'] = [res[0].time.format("YYYY-MM-DD HH:mm:ss"), res[1].time.format("YYYY-MM-DD HH:mm:ss")]
        return dic

    def __preHandling(self):
        """
        待匹配字符串的清理空白符和语气助词以及大写数字转化的预处理
        :return:
        """
        self.target = StringPreHandler.delKeyword(self.target, u"\\s+")  # 清理空白符
        self.target = StringPreHandler.delKeyword(self.target, u"[的]+")  # 清理语气助词
        self.target = StringPreHandler.numberTranslator(self.target)  # 大写数字转化

    def __timeEx(self):
        """

        :param target: 输入文本字符串
        :param timeBase: 输入基准时间
        :return: TimeUnit[]时间表达式类型数组
        """
        startline = -1
        endline = -1
        rpointer = 0
        temp = []

        match = self.pattern.finditer(self.target)
        for m in match:
            startline = m.start()
            if startline == endline:
                rpointer -= 1
                temp[rpointer] = temp[rpointer] + m.group()
            else:
                temp.append(m.group())
            endline = m.end()
            rpointer += 1
        res = []
        # 时间上下文： 前一个识别出来的时间会是下一个时间的上下文，用于处理：周六3点到5点这样的多个时间的识别，第二个5点应识别到是周六的。
        contextTp = TimePoint()
        # print(self.timeBase)
        # print('temp',temp)
        self.wordNeed2beChanged = temp
        for i in range(0, rpointer):
            # 这里是一个类嵌套了一个类
            res.append(TimeUnit(temp[i], self, contextTp))
            # res[i].tp.tunit[3] = -1
            contextTp = res[i].tp
            # print(self.nowTime.year)
            # print(contextTp.tunit)
        res = self.__filterTimeUnit(res)

        return res

    def __filterTimeUnit(self, tu_arr):
        """
        过滤timeUnit中无用的识别词。无用识别词识别出的时间是1970.01.01 00:00:00(fastTime=0)
        :param tu_arr:
        :return:
        """
        if (tu_arr is None) or (len(tu_arr) < 1):
            return tu_arr
        res = []
        for tu in tu_arr:
            if tu.time.timestamp != 0:
                res.append(tu)
        return res

    def __str2Span(self, time_span, time):
        return [time.floor(time_span).format("YYYY-MM-DD HH:mm:ss"),time.ceil(time_span).format("YYYY-MM-DD HH:mm:ss")]

    def __dist2Span(self, time_dist, time):
        if time_dist[0] == 0:
            return [time.replace(year=time_dist[1]).format("YYYY-MM-DD HH:mm:ss"),
                    time.replace(year=time_dist[2]).format("YYYY-MM-DD HH:mm:ss")]
        elif time_dist[0] == 1:
            return [time.replace(month=time_dist[1]).format("YYYY-MM-DD HH:mm:ss"),
                    time.replace(month=time_dist[2]).format("YYYY-MM-DD HH:mm:ss")]
        elif time_dist[0] == 2:
            return [time.replace(day=time_dist[1]).format("YYYY-MM-DD HH:mm:ss"),
                    time.replace(day=time_dist[2]).format("YYYY-MM-DD HH:mm:ss")]
        elif time_dist[0] == 3:
            if time_dist[1]==24:
                if time_dist[2] == 24:
                    return [time.replace(hour=23, minute=59, second=59).format("YYYY-MM-DD HH:mm:ss"),
                            time.replace(hour=23, minute=59, second=59).format("YYYY-MM-DD HH:mm:ss")]
                else:
                    return [time.replace(hour=23, minute=59, second=59).format("YYYY-MM-DD HH:mm:ss"),
                            time.replace(hour=time_dist[2]).format("YYYY-MM-DD HH:mm:ss")]
            else:
                if time_dist[2] == 24:
                    return [time.replace(hour=time_dist[1]).format("YYYY-MM-DD HH:mm:ss"),
                            time.replace(hour=23, minute=59, second=59).format("YYYY-MM-DD HH:mm:ss")]
                else:
                    return [time.replace(hour=time_dist[1]).format("YYYY-MM-DD HH:mm:ss"),
                            time.replace(hour=time_dist[2]).format("YYYY-MM-DD HH:mm:ss")]
        elif time_dist[0] == 4:
            return [time.replace(minute=time_dist[1]).format("YYYY-MM-DD HH:mm:ss"),
                    time.replace(minute=time_dist[2]).format("YYYY-MM-DD HH:mm:ss")]
        elif time_dist[0] == 5:
            return [time.replace(second=time_dist[1]).format("YYYY-MM-DD HH:mm:ss"),
                    time.replace(second=time_dist[2]).format("YYYY-MM-DD HH:mm:ss")]
