正则表达式匹配日期

时间:2015-11-01 19:00:50

标签: regex

我试图编辑一些试图从一段文本中提取日期的现有正则表达式。由于我对正则表达不太熟悉,我认为这是学习新东西的好时机。

所以我得到了以下正则表达式:

r'\b0*[1-9]?[0-9]\b'

(如果我理解的话)检索一个以0或更多0开头的数字,然后是1到9之间的零个或多个数字,以及0到9之间的1个数字。所以它匹配以下内容: / p>

10
24
01

但它也匹配以下内容(显然不是日期)

94
0000024

虽然它不匹配以下(实际上是日期):

1st
3rd
5th

所以我开始用言语表达我所需要的东西,并尝试在其背后写出正则表达式:

  1. 以空格,短划线,斜线或任何内容开头的字符串(即直接从数字开始)
    • 我的尝试:\b|-|\/
  2. 字符串中共有1或2个数字。这些数字应该在1到31之间,前导零或不是。
    • 我的尝试:[1-9]|0[1-9]|[1-2][0-9]|3[0-1]
  3. 其后是" st"," nd"," rd"," th",破折号,斜线或空格。
    • 我的尝试:st|nd|rd|th|-|\/|\b
  4. 将它们放在一起就是:\b|-|\/[1-9]|0[1-9]|[1-2][0-9]|3[0-1]st|nd|rd|th|-|\/|\b

    但这似乎根本不起作用。当我测试第二部分(数字)时,它几乎匹配了我输入的所有数字。

    我不想将此问题作为give me ze code问题,但有人可以通过指出我做错了什么来帮助我吗?我真的想学习更多使用正则表达式。

    欢迎所有提示!

    PS。我知道有些月份的日子少于31天,但我必须开始在某个地方学习......

    [编辑]

    所以要明确(@Saraiva在评论中要求这样做)。我希望它匹配以下内容:

    01
    08
    9
    28
    31
    2nd
    31st
    /31st
    -22nd/
    /25-
    

    但不是这样:

    73
    01200
    026
    /2200nd-
    (6th
    

1 个答案:

答案 0 :(得分:1)

你的正则表达式片段是正确的,你只是错误地将它们放在一起。如果你这样做:

\b|-|\/[1-9]|0[1-9]|[1-2][0-9]|3[0-1]st|nd|rd|th|-|\/|\b

你正在或(|)所有东西(所以,你匹配一个单词边界,或一个破折号,或......)。

你想要这样的东西:

(?:\b)(([1-9]|0[1-9]|[1-2][0-9]|3[0-1])(st|nd|rd|th)?)(?:\b|\/)

所以:

a word boundary (non capturing)
followed by a number 0-31
followed (eventually) by one of st nd rd th
followed by a word boundary (non capturing) or a slash

此处示例:https://regex101.com/r/zM4lI5/3

如果切换到使用环视,您可能会获得更好的结果:

(?<=\b|\/|-)((?:[1-9]|0[1-9]|[1-2][0-9]|3[0-1])(?:st|nd|rd|th)?)(?=\b|\/|-)

(?<=\b|\/|-) whatever matches the following, if preceded by this
(?=\b|\/|-)  whatever matched the preceding, if followed by this

示例:https://regex101.com/r/zM4lI5/4

编辑:

如果您只想捕获数字,我会改变这样的rexgex,玩非捕获组:

(?<=\b|\/|-)([1-9]|0[1-9]|[1-2][0-9]|3[0-1])(?:st|nd|rd|th)?(?=\b|\/|-)

编辑2:好的,我发现Python要求后视断言具有恒定的长度;在我们的示例中,\b为0,而\/-为1个字符。如果它对你有好处,我建议只使用空格而不是单词边界:

(?<=\s|\/|-)([1-9]|0[1-9]|[1-2][0-9]|3[0-1])(?:st|nd|rd|th)?(?=\b|\/|-)

此处示例:IDEONE regex101