使用Python正则表达式在表达式中进行可选匹配?

3

我已经写了下面的正则表达式来匹配命令行中人类可读的时间:

^(?:(?:(?:(\d+)d\s*)?(\d+)h\s*)?(\d+)m\s*)?(\d+)s$

使用非捕获字符串,该正则表达式能够同样地匹配以下格式的“可读时间”:
1d 2h 3m 4s
1h 2m 3s
1m 2s
1s

...and...

1d2h3m4s
1h2m3s
1m2s
1s

在这个正则表达式中,如果我包含一个minutes值,我也必须包含一个seconds值。即,我不能仅提供15m1d3m,我必须提供15m0s1d0h3m0s
是否可以扩展正则表达式以匹配后两种用例?如何做到?请注意:我不一定要求一个现成的解决方案,但是指向正确方向的指针将不胜感激。
更新:只是简短的更新,我之前使用的是Python正则表达式。

你正在使用哪个正则表达式引擎? - Unihedron
抱歉,我正在使用Python中的正则表达式。我试图将其作为一个平台无关的问题来提出。 - Deacon
2
很遗憾,没有与语言无关的正则表达式。 - Unihedron
4个回答

2
您可以使用这个模式:
\A(?=\S)(?:\d+d)?(?:\h*\d+h)?(?:\h*\d+m)?(?:\h*\d+s)?\z

这种方法是让所有元素都是可选的。在开头进行的向前查找确保至少有一个非空格字符。(换句话说,它确保至少有一个元素)


@walidtoumi:因为测试两个字符是无用的,只需要一个就可以了。 - Casimir et Hippolyte
但最小要求是1个数字+1个字母(例如:1s)吗? - walid toumi
@walidtoumi:确实如此,但这并不重要,因为一旦你知道至少有一个非空格字符,你就知道至少有一个组(无论组的长度如何)。前瞻的目的仅是检查字符串不为空,因为每个组都是可选的。它的目的不是测试字符串的长度,而只是检查是否存在一个组。 - Casimir et Hippolyte
我认为 Python 不支持 \h 横向空白转义序列(尽管未标记为这样,但此处目标平台是 Python-请参见问题的注释)。此外,原始正则表达式将天数、小时数、分钟数和秒数捕获到 $1$2$3$4 中。除此之外,我觉得它看起来不错。 - ridgerunner
@ridgerunner:Python 的 re 模块确实不支持 \h(但在 regex 模块中可用)。正如您所注意到的,这个问题没有被标记为该语言。但是,像我在原始答案中写的那样,\s 更广泛地被支持,但更不严格。至于捕获组,这并不重要。 - Casimir et Hippolyte
显示剩余2条评论

2

与其维护那个正则表达式并尝试调整它,我建议大大简化您的正则表达式:

/ *(\d+)([dhms])/gm

正则表达式示例

你可以看到它匹配了所有当前和建议的字符串。然后,您可以在代码中对两个捕获组进行后处理。


1

你的第二个文件是必须的。它后面没有问号,所以所有不包含 s 的字段都会失败。

查看演示。

http://regex101.com/r/iX5xR2/28

我已经应用了问号。

哇,太棒了。你的意思是这么简单吗?我本来以为我已经尝试过完全相同的正则表达式但没有成功。仅供记录(和将来参考),你提供的正则表达式是:^(?:(?:(?:(\d+)d\s*)?(\d+)?h?\s*)?(\d+)m\s*)?((\d+)s)?$。谢谢。 - Deacon
@DarthBob,你很接近了。我刚刚调试了一下你的正则表达式,它很好。只需要做出一个小改变 :) - vks
不好意思,我错了。当我仔细看时,发现你的正则表达式和我尝试的有些不同。再次感谢! - Deacon
1
所以...这里有一些奇怪的东西。在你的正则表达式的这个部分:(\d+)?h?\s*)?(\d+)m\s*),在h后面的?中,15m与小时位置的1和分钟位置的5匹配。如果我从h后面删除?15m将正确匹配,但是1d 5m不再匹配。 - Deacon
1
@DarthBob,你已经将d和h分组在一起了。它们在你的正则表达式中是在一起的。所以要使h可选,必须添加它。 - vks
显示剩余2条评论

0

您可以使用嵌套组:

/^(?:(?:(?:(\d+)d\s*)?(\d+)h\s*)?(\d+)m\s*)?(\d+)s$/g

dhms 的值分别在第 1、2、3 和 4 组中。

这里有一个正则表达式演示


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接