复杂的正则表达式查找日期和时间

时间:2018-09-24 08:11:06

标签: regex vba date time ms-word

有没有人可以帮助我解决以下问题:

我正在尝试在文本中找到特定的日期和时间字符串(在VBA Word中使用)。 当前正在使用以下RegEx字符串:

  

(?:([0-9] {1,2})[|-])?(?:( jan(?:uari)?| feb(?:ruari)?| m(?:aa) ?rt | apr(?:il)?| mei | jun(?:i)?| jul(?:i)?| aug(?:ustus)?| sep(?:tember | t)?| okt(? :ober)?| nov(?:ember)?| dec(?:ember)?)))?(?: |-)?(?(3)(?:在|周围|)))?(?:([ 0-9] {1,2}:[0-9] {1,2})?(?: uur | u | u)?)?

在以下文本上测试了输出:

  1. 日期,大约时间:2016年9月26日,大约09:00u
  2. 日期,时间:2016年9月1日,09:00 uur
  3. 日期和时间u:2018年9月1日09:00 u
  4. 无日期的时间:08:30 uur
  5. 日期u:2016年9月1日09:00u
  6. 仅时间:09:00
  7. 仅一个月:jan
  8. 月份和年份:2019年2月
  9. 仅一天:02
  10. 只有'-'的一天:2-
  11. 日期和月份:1月2日
  12. 月年:2018年1月
  13. 带有'-'的日期:2018年2月2日09:00
  14. 其他月份:2016年9月1日
  15. 整个月:2018年9月1日
  16. 缩短年份:18年7月

规则:

  • 日期后加上时间有效
  • 日期后加文字“ around”或“ at”,再加上时间有效
  • 没有日期的日期有效
  • 没有年份的日期有效
  • 仅日期和月份无效有效
  • 一天,没有月份或年份无效无效
  • 日期可能包含破折号'-'
  • 一年可能会以'缩短,例如jun '18
  • 月份名称可以短也可以长
  • 完全匹配包括“ uur”或“ u”(以突出显示ms-Word中的文本)
  • 捕获的子匹配文本中没有空格或尾随空格

示例:[{https://regex101.com/r/6CFgBP/1/]

预期的输出(在VBA Word中使用时): regex Matches集合对象,其中每个Match.SubMatches都包含来自regex搜索字符串中捕获组的单个项d,m,y,hh:mm。 因此,例如1:子匹配(或捕获组)包含值:'26'','sep','2016','09:00'

RegEx可以正常工作,但是需要排除一些假阳性:

  • 如果一天中没有月份/年份,则应将其排除在正则表达式之外(示例9和10)
  • 万一没有一天,应该排除在外(示例7)

(我正在尝试使用som lookahead并引用\ 1和?(1),但无法使其正常运行...)

任何建议都值得赞赏!

2 个答案:

答案 0 :(得分:0)

据我了解,您需要每个日期/时间部分(天,月,年,小时 和分钟)必须出现。

因此,您应该在相关组之后删除?(它们是可选的)。

将每个组都捕获为相关的捕获组也是一种好习惯。

无需编写类似jun(?:i)?的内容。够了 (并且更易于阅读),当您只写juni?时(?指的是 到前面的i为止。

另一个提示:由于正则表达式语言包含\d char类,因此只需使用 而不是[0-9](正则表达式更短,更易于阅读。

(在/左右)可选部分应该是可选且非捕获组。

在正则表达式中不需要分钟部分之后的任何内容。

因此,我提出了如下所示的正则表达式(为了便于阅读,我将其分为几行):

(\d{1,2})[ -](jan(?:uari)?|feb(?:ruari)?|m(?:aa)?rt|apr(?:il)?|mei|juni?
|juli?|aug(?:ustus)?|sep(?:tember|t)?|okt(?:ober)?|nov(?:ember)?|dec(?:ember)?)
[ -](\d{4}) (?:around |at )?(\d{1,2}:\d{1,2})

详细信息:

  • (\d{1,2})-天。
  • [ -]-一天后的分隔符(空格或减号)。
  • (jan(?:uari)?|...dec(?:ember)?)-月。
  • [ -]-月后的分隔符。
  • (\d{4})-年。
  • (?:around |at )?-实际上,年份之间有3种分隔符 和小时(空格/ 左右 / at ),请注意(...)之前的空格?
  • (\d{1,2}:\d{1,2})-小时和分钟。

它匹配变体1,2,3,5和13。 其余所有内容均未包含每个必需的部分,因此它们不匹配。

如果您允许例如时/分部分是可选的,请更改相应的片段 进入:

( (?:around |at )?(\d{1,2}:\d{1,2}))?

即用()?周围/周围/时/分部分包围起来, 使这部分成为可选组。然后,变体14和15也将 被匹配。

另外一个扩展名:如果您还单独允许小时/分钟部分 , 将|(\d{1,2}:\d{1,2})添加到正则表达式(第一个变量之前, 添加的部分是小时/分钟的第二个变体。

然后,您的4号和6号变体也会匹配。

有关工作示例,请参见https://regex101.com/r/33t1ps/1

编辑

在您列出规则之后,我提出以下正则表达式:

  • (\d{1,2}[ -])?-日期+分隔符,可选。
  • (jan(?:uari)?|...|dec(?:ember)?)-月。
  • (?:[ -](\d{4}|'\d{2}))?-分隔符+年(带“'”的4位或2位数字)。
  • ( (?:around |at )?(\d{1,2}:\d{1,2}))?-分隔符+小时/分钟- 变体1的可选结尾。
  • |(\d{1,2}:\d{1,2})-变体2-仅小时和分钟。

它不仅与您的版本9和10匹配。

有关完整的正则表达式,也包括“ uur”,请参见https://regex101.com/r/33t1ps/3

答案 1 :(得分:0)

最后,我发现了一些可以帮助我正确使用月份的方法:-)

\b(?:([1-3]|[0-3]\d)[ |-](?'month'(?:[1-9]|\d[12])|(?:jan(?:uari)?|feb(?:ruari)?|m(?:aa)?rt|apr(?:il)?|mei|jun(?:i)?|jul(?:i)?|aug(?:ustus)?|sep(?:tember|t)?|okt(?:ober)?|nov(?:ember)?|dec(?:ember)?))?)?(?:(\g'month')[ |-]((?:19|20|\')(?:\d{2})))?\b(?: omstreeks | om | )?(?:(\d{1,2}[:]\d{2}(?: uur|u)?|[0-2]\d{3}(?: uur|u)))?\b

它使用命名的构造函数/子例程。在这里找到: https://www.regular-expressions.info/subroutine.html