表达式捕获组的问题

Issue with a expression capturing groups

我有一些这样的数据

Wed Mar 18 15:16:10 2015 eth0:1 109.224.232.219 up (not currently mapped)
Wed Mar 18 15:18:12 2015 eth0:1 109.224.232.219 down (not responding)
Wed Mar 18 15:20:46 2015 eth0:1 109.224.232.219 up (not currently mapped)
Wed Mar 18 15:22:52 2015 eth0:1 109.224.232.219 down (not responding)
Wed Mar 18 15:24:26 2015 eth0:1 109.224.232.219 up (not currently mapped)

我试图在每一行中捕获 IP 和日期字符串,我想我可以在 eth 之前做任何事情然后我的 IP 检查,但这不起作用。我是否误解了捕获组的概念?

是否有从 1 个正则表达式获取此数据的明智方法?

(^(.*?)eth)(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})

如有任何帮助,我们将不胜感激。

这是当前正则表达式的图像

https://www.debuggex.com/i/BaXnqh2DzRhUCph8.png

你快到了。您只需要在 eth 之后添加 .*? 以便它匹配 eth 和 ip 地址之间的字符。

^(.*?)eth.*?\b(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})

DEMO

如果您不希望 eth 之前的 space 不被第 1 组捕获,那么您可以像这样更改您的正则表达式,

^(.*?)\s+eth.*?\b(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})

DEMO

有时,人们会忽略点分十进制 IP 表示形式的明确定义的字符序列。当我完全详细说明正确的 IP 八位字节时,我几乎 没有 识别 IP 的问题。

my $octet  = qr/\b(?:0|1\d{0,2}|2(?:[0-4]\d?|5[0-5]?|[6-9])?|[3-9]\d?)\b/;
my ( $foctet = "$octet" ) =~ s/0[|]//;

然后最重要的是,我指定 IP 地址是一组四个八位字节,用点分隔。

my $ip_regex = qr/($foctet(\.$octet){3})/;

这个小美女几乎总是会为我从任何文件中提取任何有效的 IP。

除此之外,还可以更详细地指定日期。再一次,按照这个规范,你得到的几乎不可避免地是一个日期:

my $dow            = qr/\b(?:Fri|Mon|Sat|Sun|Thu|Tue|Wed)\b/;
my $mon            = qr/\b(?:Apr|Aug|Dec|Feb|Jan|Jul|Jun|Mar|May|Nov|Oct|Sep)\b/;
my $day            = qr/\b(?:[012]\d?|3[01]?|[4-9])\b/;
my $hr24           = qr/\b(?:[01]\d?|2[0-3])\b/;
my $minsec         = qr/\b(?:[0-5]\d)\b/;
my $datetime_regex = qr/$dow\s+$mon\s+$day\s+$hr24:$minsec:$minsec\s+\d+/;

因此,只需对源代码行使用两个正则表达式,您就可以得到想要的结果,而无需大量回溯。

my @date_parts = $line =~ /$datetime_regex/;
my ( $ip )     = $line =~ /$ip_regex/;

事实上,如果性能是一个问题,我看到在非贪婪匹配的单个正则表达式中有很多失败,而 ip 正则表达式在第一次尝试时就成功了。正则表达式引擎找到“.”在偏移量 35 处开始回到位置 32。

但是,下面的两个都不会失败一次。只是说明它如何帮助将表达式指定为预期的数据范围:

my ( $dt, $ip ) = m/($datetime_regex)\s+eth\d:\d+\s+($ip_regex)/;