将日期与分隔值的相同字符匹配

时间:2017-04-21 17:29:14

标签: python regex

我必须在文本中找到多种格式的日期。 我有一些像这样的正则表达式:

# Detection of:
# 25/02/2014 or 25/02/14 or 25.02.14
regex = r'\b(0?[1-9]|[12]\d|3[01])[-/\._](0?[1-9]|1[012])[-/\._]((?:19|20)\d\d|\d\d)\b'

问题在于它还匹配25.02/14之类的日期,因为分裂字符不同,所以它不合适。

我当然可以为每个正则表达式使用不同的分裂字符进行多个正则表达式,或者对匹配结果进行后处理,但我更喜欢只使用一个正则表达式的完整解决方案。有办法吗?

2 个答案:

答案 0 :(得分:1)

根据Rawing的评论,这就是诀窍:

regex = r'\b(0?[1-9]|[12]\d|3[01])([./-])(0?[1-9]|1[012])\2((?:19|20)\d\d|\d\d)\b'

所以,完整的代码是:

import re

s = '25.02/2014 25.02/14 11/12/98 11/12/1998 14/12-2014 14-12-2014 14.12.1998'

found_dates = []
for m in re.finditer(r'\b(0?[1-9]|[12]\d|3[01])([./-])(0?[1-9]|1[012])\2((?:19|20)\d\d|\d\d)\b', s):
    found_dates.append(m.group(0))
print(found_dates)

根据需要输出: ['11/12/98', '11/12/1998', '14-12-2014', '14.12.1998']

答案 1 :(得分:1)

my comment之外(原始字边界方法允许模式匹配“日期”,实际上是其他实体的部分,如IP,序列号,产品ID等),请参阅改进版本你的正则表达式与你的相比:

import re

s = '25.02.19.35  6666-20-03-16-67875 25.02/2014 25.02/14 11/12/98 11/12/1998 14/12-2014 14-12-2014 14.12.1998'

found_dates = [m.group() for m in re.finditer(r'\b(?:0?[1-9]|[12]\d|3[01])([./-])(?:0?[1-9]|1[012])\1(?:19|20)?\d\d\b', s)]
print(found_dates) # initial regex

found_dates = [m.group() for m in re.finditer(r'(?<![\d.-])(?:0?[1-9]|[12]\d|3[01])([./-])(?:0?[1-9]|1[012])\1(?:19|20)?\d\d(?!\1\d)', s)]
print(found_dates) # fixed boundaries

# = >['25.02.19', '20-03-16', '11/12/98', '11/12/1998', '14-12-2014', '14.12.1998']
# => ['11/12/98', '11/12/1998', '14-12-2014', '14.12.1998']

请参阅,您的正则表达式提取'25.02.19'(潜在IP的一部分)和'20-03-16'(潜在序列号/产品ID的一部分)。

注意我还略微缩短了正则表达式和提取代码。

模式详情

  • (?<![\d.-]) - 一个负面的背后隐藏确保当前位置左侧没有数字. -/已被丢弃,因为日期是经常在网址内找到)
  • (?:0?[1-9]|[12]\d|3[01]) - 01 / 131(白天)
  • ([./-]) - 第1组(保留分隔符值的技术组)与./-
  • 匹配
  • (?:0?[1-9]|1[012]) - 月份部分:01 / 112
  • \1 - 反向引用第1组值以确保相同的分隔符来到此处
  • (?:19|20)?\d\d - 年份:1920(可选值),然后是任意两位数。
  • (?!\1\d) - 负向前瞻,确保没有分隔符(捕获到第1组),然后紧跟当前位置右侧的任何数字。