我正在使用pyLR1编写自定义描述语言的词法规则,其中包括时间文字,例如:
10h30m # meaning 10 hours + 30 minutes
5m30s # meaning 5 minutes + 30 seconds
10h20m15s # meaning 10 hours + 20 minutes + 15 seconds
15.6s # meaning 15.6 seconds
小时,分钟和秒钟部分的规格顺序应固定为h
,m
,s
。要详细说明,我需要以下有效组合hms
,hm
,h
,ms
,m
和s
(带数字)当然不同的部分之间)。
作为奖励,正则表达式应检查段中的十进制(即非自然)数字,并且仅在具有最小重要性的段中允许这些数字。
所以我除了最后一组之外的所有人都有一个数字匹配:
([0-9]+)
对于最后一组甚至:
([0-9]*\.[0-9]+|[0-9]+(\.[0-9]*)?) # to allow for .5 and 0.5 and 5.0 and 5
通过h,m和s的所有组合,一个可爱的小蟒蛇脚本给了我以下正则表达式:
(([0-9]*\.[0-9]+|[0-9]+(\.[0-9]*)?)h|([0-9]+)h([0-9]*\.[0-9]+|[0-9]+(\.[0-9]*)?)m|([0-9]+)h([0-9]+)m([0-9]*\.[0-9]+|[0-9]+(\.[0-9]*)?)s|([0-9]*\.[0-9]+|[0-9]+(\.[0-9]*)?)m|([0-9]+)m([0-9]*\.[0-9]+|[0-9]+(\.[0-9]*)?)s|([0-9]*\.[0-9]+|[0-9]+(\.[0-9]*)?)s)
显然,这是一个有点恐怖的表达。有什么方法可以简化这个吗?答案必须与pythons re
模块一起使用,如果由于其正则表达式的受限子集,我也会接受不适用于pyLR1
的答案。
答案 0 :(得分:3)
您可以使用符号h
,m
,s
来表示正则表达式,以表示每个子目标,最基本的版本是:
h|hm|hms|ms|m|s
这是你目前所拥有的。你可以将其分解为:
(h|hm|hms)|(ms|m)|s
然后从第一个表达式中提取h
,从第二个表达式中提取m
(使用(x|)
== x?
):
h(m|ms)?|ms?|s
继续我们进入
h(ms?)?|ms?|s
这可能更简单(也可能是最简单的)。
添加正则表达式d
来表示小数(如\.[0-9]+
中所示),这可以写成
h(d|m(d|sd?)?)?|m(d|sd?)?|sd?
(即每个阶段可选择有小数,或者继续h
m
或s
的下一个。)
这会产生类似的东西(只需几小时和几分钟):
[0-9]+((\.[0-9]+)?h|h[0-9]+(\.[0-9]+)?m)|[0-9]+(\.[0-9]+)?m
考虑到这一点,可能无法进入一个适用于pyLR1的表单,因此在每个点进行小数点解析,然后进行二次检查可能是最好的方法。
答案 1 :(得分:1)
下面的表示应该是可以理解的,我不知道你正在使用的正确的正则表达式语法,所以你必须自己“翻译”到有效的语法。
你的营业时间
[0-9]{1,2}h
你的会议纪要
[0-9]{1,2}m
你的秒数
[0-9]{1,2}(\.[0-9]{1,3})?s
你想要所有那些按顺序,并且能够省略其中任何一个(用?
包裹)
([0-9]{1,2}h)?([0-9]{1,2}m)?([0-9]{1,2}(\.[0-9]{1,3})?s)?
然而,匹配的内容如下:10h30s
有效组合包括hms
,hm
, hs
,h
,ms
,m
和{{ 1}}
或者说,分钟可以被省略,但仍然有几小时和几秒钟。
另一个问题是如果给出空字符串,则匹配,因为所有三个s
都有效。所以你必须以某种方式解决这个问题。 HMM的
查看@dbaupp ?
您可以采取上述内容并匹配:
h(ms?)?|ms?|s
所以你得到:
h: [0-9]{1,2}h
m: [0-9]{1,2}m
s: [0-9]{1,2}(\.[0-9]{1,3})?s
所有这些OR一起给你一个很大但很容易打破的正则表达式:
h(ms?)?: ([0-9]{1,2}h([0-9]{1,2}m([0-9]{1,2}(\.[0-9]{1,3})?s)?)?
ms? : [0-9]{1,2}m([0-9]{1,2}(\.[0-9]{1,3})?s)?
s : [0-9]{1,2}(\.[0-9]{1,3})?s
可以解决空字符串问题和 ([0-9]{1,2}h([0-9]{1,2}m([0-9]{1,2}(\.[0-9]{1,3})?s)?)?|[0-9]{1,2}m([0-9]{1,2}(\.[0-9]{1,3})?s)?|[0-9]{1,2}(\.[0-9]{1,3})?s
的匹配问题。
关注@Donal Fellows对@dbaupp回答的评论,我也会做hs
(h?m)?S|h?M|H
并合并在一起,你最终会得到比上面更小的东西:
(h?m)?s: (([0-9]{1,2}h)?[0-9]{1,2}m)?[0-9]{1,2}(\.[0-9]{1,3})?s
h?m : ([0-9]{1,2}h)?[0-9]{1,2}m
h : [0-9]{1,2}h
现在我们必须找到一种匹配(([0-9]{1,2}h)?[0-9]{1,2}m)?[0-9]{1,2}(\.[0-9]{1,3})?s|([0-9]{1,2}h)?[0-9]{1,2}m|[0-9]{1,2}h
化学表示的方法
答案 2 :(得分:1)
这是一个简短的Python表达式that works:
(\d+h)?(\d+m)?(\d*\.\d+|\d+(\.\d*)?)(?(2)s|(?(1)m|[hms]))
受Cameron Martins answer的启发,基于条件限制。
(\d+h)? # optional int "h" (capture 1)
(\d+m)? # optional int "m" (capture 2)
(\d*\.\d+|\d+(\.\d*)?) # int or decimal
(?(2) # if "m" (capture 2) was matched:
s # "s"
| (?(1) # else if "h" (capture 1) was matched:
m # "m"
| # else (nothing matched):
[hms])) # any of the "h", "m" or "s"
答案 3 :(得分:0)
您可能有几小时,几分钟和几秒钟。
/(\d{1,2}h)*(\d{1,2}m)*(\d{1,2}(\.\d+)*s)*/
应该做的工作。根据正则表达式库,您将按顺序获取项目,或者您必须进一步解析它们以检查h,m或s。
在后一种情况下,另请参阅
返回的内容 /(\d{1,2}(h))*(\d{1,2}(m))*(\d{1,2}(\.\d+)*(s))*/
答案 4 :(得分:0)
最后一组应该是:
([0-9]*\.[0-9]+|[0-9]+(\.[0-9]+)?)
除非您想匹配5.
您可以使用regex ifs,如下所示:
(([0-9]+h)?([0-9]+m)?([0-9]+s)?)(?(?<=h)(([0-9]*\.[0-9]+|[0-9]+(\.[0-9]*)?)m)?|(?(?<=m)(([0-9]*\.[0-9]+|[0-9]+(\.[0-9]*)?)s)?|\b(([0-9]*\.[0-9]+|[0-9]+(\.[0-9]*)?)[hms])?))
我没有检查过这是否有效,但它只是将整数与小时,分钟,然后是秒匹配,然后如果匹配的最后一个是小时,则允许小数分钟,否则如果匹配的最后一个是分钟,它允许小数秒。