Perl Regex - 从maillog中提取ipv4

时间:2017-09-01 08:13:21

标签: regex perl ipv4

我正在使用perl / mysql / iptables中的分布式fail2ban系统。

从/ var / log / messages中提取ipv4地址是有效的,但现在 我想将/ var / log / maillog添加到汤中。

我有一个perl正则表达式: [1]

/ (?:25[012345]|2[0-4]\d|1?\d\d?)\.
  (?:25[012345]|2[0-4]\d|1?\d\d?)\.
  (?:25[012345]|2[0-4]\d|1?\d\d?)\.
  (?:25[012345]|2[0-4]\d|1?\d\d?) /x

来自maillog的一句话:

v817YjcU016645: 194.102.60.190.host.ifxnetworks.com [190.60.102.194] did not issue MAIL/EXPN/VRFY/ETRN during connection to MTA

此处正则表达式与194.102.60.190。host.ifxnetworks.com匹配 和[190.60.102.194]

在我的代码中我有($ IP是上面的正则表达式):

if ($line =~ m/($IP)/)
{
    my ($ip) = $1;

此处找到第一个匹配的类似ip的字符串194.102.60.190。host.ifxnetworks.com

那么,如何让正则表达式忽略以.

结尾的ipv4

[1] 的可读性Perl支持/x option

2 个答案:

答案 0 :(得分:4)

如果这是唯一的问题,请尝试使用negative lookahead

my ($ip) = $line =~ /($IP)(?![.\d])/;

适用于显示的数据。

前瞻中的字符类[.\d]是必需的,因为$IP正则表达式中的最后一个术语允许通过\d?获得可变数字的数字。因此,仅使用(?!\.)引擎就可以匹配少于一个数字的数字,然后该剩余数字满足非.限制。 *

因此,我们需要在模式之后禁止.和数字。

完整的程序

use warnings;
use strict;

my $t = 'a 194.102.60.190.host.ifxnetworks.com [190.60.102.194] b';

my $n = qr/(?:25[012345]|2[0-4]\d|1?\d\d?)/;

my $IP = qr/$n\.$n\.$n\.$n/;

my @m = $t =~ /($IP)(?![.\d])/g;

print "@m\n";

打印190.60.102.194

* 考虑子串90.host。它的模式/\d\d?(?!\.)/的工作原理如下。

第一个\d匹配9。但是下一个\d?是可选的(非贪婪),如果模式的其余部分可以匹配,则不匹配。实际上,(?!\.)认为以下0不是.,因此我们匹配90满足(?!\.)。整个模式(错误地)匹配

perl -wE'$_ = q(90.host); @m = /(\d)(\d?)(?!\.)(.)/; say for @m'

打印

9

0

中间捕获组没有任何内容,下一个字符(.)0

现在考虑相同子字符串的模式/\d\d?(?![.\d])/(?![.\d])要求以下内容既不是. 也不是数字。因此,可选的\d?被强制匹配下一个数字0。由于下一个字符 a .,因此模式失败。

在单行而不是(?![.\d])中使用(?!\.),不会打印任何内容,因为模式根本不匹配。 (在某些shell中,您可能必须转义!,所以(?\![.\d])或使用脚本。)

引擎可能不会如上所述完全,这更像是对其操作的松散描述。

答案 1 :(得分:0)

一般来说,正则表达式与现有字符序列中的所需模式匹配,如果存在不需要的东西,则总是有点难以匹配。

您可以匹配后跟非点([^.])的IP地址 [1]

(?:\d{1,3}\.){3}\d{1,3}[^.]

和该行末尾的IP地址($):

(?:\d{1,3}\.){3}\d{1,3}$

您可以通过更改(|)在非捕获组((?: ... ))中合并这两种模式:

(?:\d{1,3}\.){3}\d{1,3}(?:[^.]|$)

类似的问题可能是您的下一个任务可能是排除在他们之前有一个点的IP地址,另一个问题是它也会匹配2.3.4.5中的1.2.3.4.5,这会导致我的介绍性陈述......

我认为您尝试匹配的IP地址最适合检查周围字符的内容。要明确这一点。对于开发阶段,尝试通过将它们与“垃圾模式”匹配来检查不匹配的行。在问题所示的情况下(空格和括号是可接受的环境),我建议使用

(?:[ \[]|^)((?:\d{1,3}\.){3}\d{1,3})(?:[ \]]|$)

[1] 我在这里使用简化的正则表达式,它也匹配333.333.333.333000.000.000.000,当然可以改进它以限制匹配到有效的IP地址,但解决方法是abundant