in Python/libraries/recognizers-date-time/recognizers_date_time/date_time/base_merged.py [0:0]
def parse(self, source: ExtractResult, reference: datetime = None) -> Optional[DateTimeParseResult]:
if not reference:
reference = datetime.now()
# Push, save the MOD string
has_before = False
has_after = False
has_since = False
has_around = False
has_equal = False
has_date_after = False
match_is_after = False
# "inclusive_mod" means MOD should include the start/end time
# For example, cases like "on or later than", "earlier than or in" have inclusive modifier
has_inclusive_mod = False
mod_str = ''
if source.meta_data and source.meta_data.has_mod:
before_match = RegExpUtility.match_begin(self.config.before_regex, source.text, True)
after_match = RegExpUtility.match_begin(self.config.after_regex, source.text, True)
since_match = RegExpUtility.match_begin(self.config.since_regex, source.text, True)
preLength = 0
if before_match and before_match.success:
preLength = before_match.index + before_match.length
elif after_match and after_match.success:
preLength = after_match.index + after_match.length
elif since_match and since_match.success:
preLength = since_match.index + since_match.length
aroundText = source.text[preLength:]
around_match = RegExpUtility.match_begin(self.config.around_regex, aroundText, True)
equal_match = RegExpUtility.match_begin(self.config.equal_regex, source.text, True)
if before_match and not before_match.success:
before_match = RegExpUtility.match_end(self.config.before_regex, source.text, True)
match_is_after = match_is_after or before_match.success
if after_match and not after_match.success:
after_match = RegExpUtility.match_end(self.config.after_regex, source.text, True)
match_is_after = match_is_after or after_match.success
if since_match and not since_match.success:
since_match = RegExpUtility.match_end(self.config.since_regex, source.text, True)
match_is_after = match_is_after or since_match.success
if around_match and not around_match.success:
around_match = RegExpUtility.match_end(self.config.around_regex, source.text, True)
match_is_after = match_is_after or around_match.success
if equal_match and not equal_match.success:
equal_match = RegExpUtility.match_end(self.config.equal_regex, source.text, True)
match_is_after = match_is_after or equal_match.success
if around_match and around_match.success:
has_around = True
source.start += 0 if match_is_after else preLength + around_match.index + around_match.length
source.length -= around_match.length if match_is_after else preLength + around_match.index + around_match.length
source.text = source.text[0:source.length] if match_is_after else source.text[preLength + around_match.index + around_match.length:]
mod_str = around_match.group() if match_is_after else aroundText[0:around_match.index + around_match.length]
if before_match and before_match.success:
has_before = True
if not (around_match and around_match.success):
source.start += 0 if match_is_after else before_match.length
source.length -= before_match.length
source.text = source.text[0:source.length] if match_is_after else source.text[before_match.length:]
mod_str = before_match.group() + mod_str
if RegExpUtility.get_group(before_match.match[0], "include"):
has_inclusive_mod = True
elif after_match and after_match.success:
has_after = True
if not (around_match and around_match.success):
source.start += 0 if match_is_after else after_match.length
source.length -= after_match.length
source.text = source.text[0:source.length] if match_is_after else source.text[after_match.length:]
mod_str = after_match.group() + mod_str
if RegExpUtility.get_group(after_match.match[0], "include"):
has_inclusive_mod = True
elif since_match and since_match.success:
has_since = True
if not (around_match and around_match.success):
source.start += 0 if match_is_after else since_match.length
source.length -= since_match.length
source.text = source.text[0:source.length] if match_is_after else source.text[since_match.length:]
mod_str = since_match.group() + mod_str
elif equal_match and equal_match.success:
has_equal = True
source.start += 0 if match_is_after else equal_match.length
source.length -= equal_match.length
source.text = source.text[0:source.length] if match_is_after else source.text[equal_match.length:]
mod_str = equal_match.group()
elif source.type == Constants.SYS_DATETIME_DATEPERIOD and \
regex.search(self.config.year_regex, source.text) or source.type == Constants.SYS_DATETIME_DATE or \
source.type == Constants.SYS_DATETIME_TIME:
# This has to be put at the end of the if, or cases like "before 2012" and "after 2012"
# would fall into this
# 2012 or after/above
# 3 pm or later
match = RegExpUtility.match_end(self.config.suffix_after, source.text, True)
if match and match.success:
has_date_after = True
source.length -= match.length
source.text = source.text[0:source.length]
mod_str = match.group()
result = self.parse_result(source, reference)
if not result:
return None
# Pop, restore the MOD string
if has_before and result.value:
result.length += len(mod_str)
result.start -= 0 if match_is_after else len(mod_str)
result.text = result.text + mod_str if match_is_after else mod_str + result.text
val = result.value
val.mod = self.combine_mod(val.mod, TimeTypeConstants.BEFORE_MOD if not has_inclusive_mod else
TimeTypeConstants.UNTIL_MOD)
if has_around:
val.mod = self.combine_mod(TimeTypeConstants.APPROX_MOD, val.mod)
has_around = False
result.value = val
if has_after and result.value:
result.length += len(mod_str)
result.start -= len(mod_str)
result.text = mod_str + result.text
val = result.value
val.mod = self.combine_mod(val.mod, TimeTypeConstants.AFTER_MOD if not has_inclusive_mod else
TimeTypeConstants.SINCE_MOD)
if has_around:
val.mod = self.combine_mod(TimeTypeConstants.APPROX_MOD, val.mod)
has_around = False
result.value = val
if has_since and result.value:
result.length += len(mod_str)
result.start -= len(mod_str)
result.text = mod_str + result.text
val = result.value
val.mod = TimeTypeConstants.SINCE_MOD
if has_around:
val.mod = self.combine_mod(TimeTypeConstants.APPROX_MOD, val.mod)
has_around = False
result.value = val
if has_around and result.value:
result.length += len(mod_str)
result.start -= len(mod_str)
result.text = mod_str + result.text
val = result.value
val.mod = TimeTypeConstants.APPROX_MOD
result.value = val
if has_equal and result.value:
result.length += len(mod_str)
result.start -= len(mod_str)
result.text = mod_str + result.text
if has_date_after and result.value:
result.length += len(mod_str)
result.text = result.text + mod_str
val = result.value
val.mod = self.combine_mod(val.mod, TimeTypeConstants.SINCE_MOD)
result.value = val
has_since = True
# For cases like "3 pm or later on monday"
match = self.config.suffix_after.match(result.text)
if result.value and (match.start() != 0 if match else match) and \
result.type == Constants.SYS_DATETIME_DATETIME:
val = result.value
val.mod = self.combine_mod(val.mod, TimeTypeConstants.SINCE_MOD)
result.value = val
has_since = True
if self.options & DateTimeOptions.SPLIT_DATE_AND_TIME and result.value and result.value.sub_date_time_entities:
result.value = self._date_time_resolution_for_split(result)
else:
result = self.set_parse_result(
result, has_before, has_after, has_since)
return result