我的文本文件中有以下时间格式
`1` equals one second.
`5|01` equals five minutes and one seconds.
`13|01` equals thirteen minutes and one seconds.
`21|12|01` equals 21 hours, 12 minutes, and 1 seconds.
我需要 egrep 任何超过五分钟的时间。我正在使用以下正则表达式,但它不起作用,因为它排除了诸如 之类的时间13|00
。
'[[:space:]0-9][[:space:]0-9][[:space:]|][[:space:]0-9][[:space:]6-9][|][0-9][0-9]'
这是一个例子:
lite on 1
lite on 01
lite on 5|22
lite on 23|14
lite on 1|14|23
答案1
忽略空格(您可以稍后自己填写)和可能的前导零(同样),您希望匹配任何
[5-9]\|[0-9]+
[1-9][0-9]\|[0-9]+
[0-9]+\|[0-9]+\|[0-9]+
对于范围内的时间
[5,10) minutes
[10,99) minutes
1+ hours
分别。
因此,将它们加入到一个匹配组中,(...|...)
并在开头和结尾处进行足够的锚定(这样您就不会匹配14|59
或1|00|00
)。
这给出了
grep -E 'on +([5-9]\|[0-9]+|[1-9][0-9]\|[0-9]+|[0-9]+\|[0-9]+\|[0-9]+) *$'
我们可以稍微简化一下,因为秒对于所有三个正则表达式都是通用的:
grep -E 'on +([5-9]|[1-9][0-9]|[0-9]+\|[0-9]+)\|[0-9]+ *$'
答案2
这应该有效:
grep -E '( [0-9]{1,2}\|[0-9]{1,2}\|[0-9][1-9] )|( [0-9][0-9]\|[0-9]{2,2} )|( [5-9]\|[0-9][1-9] )|( [6-9]\|[0-9][0-9] )' <file>
基本上,您正在创建 4 个模式,它们封装在' 中,并用'()
分隔。|
的|
行为与or
正则表达式中相同。
这些{1,2}
零件是1-2 instances of preceding pattern
如此[0-9]{1,2}
意味着1-2 instances of 0-9
or
之后,我们通过语法为所有可能的数字组合创建一个基本测试用例
答案3
不要使用grep
.正则表达式用于匹配模式,但它们对于匹配值来说确实很糟糕。您也许可以做到,但您使用锤子作为螺丝刀。从技术上讲,它是可行的,但它很混乱且效率低下。
所以与其:
#!/usr/bin/env perl
use strict;
use warnings;
while (<DATA>) {
my @numbers = m/(\d+)/g;
my $seconds = pop(@numbers);
$seconds += ( pop(@numbers) // 0 ) * 60; #second digit minutes -> seconds
$seconds
+= ( pop(@numbers) // 0 ) * 60 * 60; #third digit, hours -> seconds;
print if $seconds > 300;
}
__DATA__
lite on 1
lite on 01
lite on 5|22
lite on 23|14
lite on 1|14|23
这打印:
lite on 5|22
lite on 23|14
lite on 1|14|23
您可以将其简单化为:
perl -ne 'for ( m/(\d+)/g ) { $t *= 60; $t += $_ }; print if $t > 300;'
对于奖励点 - 这可以应对相当任意的验证标准,没有太大的困难,并且如果您决定有一天 grep 获取不同的值,则不需要太多的修改。
但上面的工作原理是:
- 使用
m/(\d+)/g
- 作为g
匹配,意味着它将“一个或多个数字”的重复实例选择到数组中。 (@numbers
或者就像第二个示例中 for 循环中的自包含迭代器一样)。 - 它通过乘以 60 将该数字链转换为秒。(如果您添加天数,则效果不会那么好!)
- 然后测试该数字是否大于 300 - 即 5 分钟(以秒为单位)。