【问题标题】:Issue with a expression capturing groups表达式捕获组的问题
【发布时间】:2015-04-06 15:41:58
【问题描述】:

我有一些这样的数据

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

【问题讨论】:

    标签: regex perl expression capture


    【解决方案1】:

    你快到了。您只需在eth 之后添加.*?,这样它就可以匹配eth 和IP 地址之间的字符。

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

    DEMO

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

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

    DEMO

    【讨论】:

    • 我不得不等 8 分钟 :P
    【解决方案2】:

    有时,人们会忽略点分十进制 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)/;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-04-16
      • 1970-01-01
      • 1970-01-01
      • 2021-07-09
      • 1970-01-01
      • 2017-07-22
      • 2015-07-24
      相关资源
      最近更新 更多