【问题标题】:Complex Regex finding date and time复杂的正则表达式查找日期和时间
【发布时间】:2019-02-27 17:08:46
【问题描述】:

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

我正在尝试在文本中查找特定的日期和时间字符串(在 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)(?: | at | ))?(?:([ 0-9]{1,2}:[0-9]{1,2})?(?: uur| u|u)?)?

以下文本的测试输出:

  1. 日期时间:2016 年 9 月 26 日 09:00 左右
  2. 日期时间:2016 年 9 月 1 日 09:00 uur
  3. 你的日期和时间:2018 年 9 月 1 日 09:00 你
  4. 没有日期的时间:08:30 uur
  5. 日期与时间 u:2016 年 9 月 1 日 09:00u
  6. 仅时间:09:00
  7. 仅一个月:一月
  8. 月份和年份:2019 年 2 月
  9. 只有一天:02
  10. 只有带“-”的一天:2-
  11. 日期和月份:1 月 2 日
  12. 月份年份:2018 年 1 月
  13. 带有“-”的日期:2-feb-2018 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 中使用时): 一个正则表达式匹配集合对象,其中每个 Match.SubMatches 包含来自正则表达式搜索字符串中捕获组的单个项目 d、m、y、hh:mm。 例如1:子匹配(或捕获组)包含值:'26'','sep','2016','09:00'

RegEx 工作正常,但需要排除一些误报:

  • 如果某天没有月/年,则应从 Regex 中排除(示例 9 和 10)
  • 如果有一个月没有一天,应该排除(示例7)

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

任何建议都非常感谢!

【问题讨论】:

  • 你想从你的测试字符串中得到什么输出?
  • 快速回复 :-) 我在 Matches.SubMatches VBA 对象中使用捕获组。因此,即对于第 1 项:Match 返回一个具有子匹配“26”、“sep”、“2016”、“09:00”的对象
  • 试试this pattern。您可以分析子匹配并相应地构建您需要的结果。
  • 感谢您查看该模式。示例 7、9 和 10 中仍然存在问题。我想不匹配这些项目的模式。
  • 这不是正则表达式的问题。当您检查 submatches(x) 长度时,您可以轻松找出匹配时要保留和拒绝的内容。

标签: regex vba date time ms-word


【解决方案1】:

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

\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

【讨论】:

  • 其中 'omstreeks' 和 'at' 对应于 'around' 和 'at'(本地语言)
  • 这是一个 PCRE 模式,它在 MS Word VBA 中不起作用。
【解决方案2】:

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

所以你应该在相关组之后删除?(它们不是可选的)。

将每个组捕获为相关的捕获组也是一种很好的做法。

没有必要写像jun(?:i)? 这样的东西。就够了 (并且更容易阅读)当您只写 juni?? 仅指 到前面的i)。

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

可选部分(at / around)应该是一个可选且非捕获组。

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

所以我提出了一个如下的正则表达式(为了便于阅读,我把它分成了几行):

(\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}))?

即用()?包围space/around/at/hour/minute部分, 使这部分成为可选组。然后,变体 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 - 仅小时和分钟。

它不只匹配您的变体 No 9 和 10。

对于完整的正则表达式,包括“uur”,请参阅https://regex101.com/r/33t1ps/3

【讨论】:

  • 感谢您的想法。我确实可以将\d 用于数字。它的可读性更好。不过,我想匹配 8、11、12、16。因此,日+月或月+年的组合对匹配有效。即便如此,也只有一年。但是文本中的单个数字,例如 9、10,是无效的,即使是单个月份名称,例如 7
  • 除此之外,捕获的项目与我是否正在寻找,即示例 13。捕获的文本出现两次:<space>09:0009:00
  • 用“我的规则”更新了问题
  • 谢谢!只有示例 9 匹配。这不应该是由于“没有日/年的月份无效”
猜你喜欢
  • 1970-01-01
  • 2019-02-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-07-11
  • 2014-07-17
  • 1970-01-01
  • 2019-01-07
相关资源
最近更新 更多