2013-07-19 165 views
1

我试图解析其具有这种模式用perl正则表达式

src [interface_name:source_address[/source_port]] 

,其中括号中的部分是可选的字符串捕获可选的字符串。因此,有3种可能的变体

src 
src LAN:10.115.1.204 
src LAN:10.115.1.204/8080 

我想捕捉的接口,从这个字符串源IP源端口

我的第三变型正则表达式是

($srcinterface,$srcip,$src_port) = m/^src (.*?):(.*?)\/(.*?)/; 

但我不知道如何使所有变种3工作的正则表达式。

编辑 问题的更大的部分是,像src dst信息也从系统收到,我需要重复正则表达式。请参见下面的字符串: -

src dst outside:125.22.32.192 
src outside:182.201.183.178 dst outside:125.22.32.192 
src outside:182.201.183.178/5525 dst outside:125.22.32.192/8595 
+0

在这个新例子中,你需要准确捕捉什么?请,你能给你第二条线所需的所有领域吗? –

+0

@CasimiretHippolyte在第二行我需要'srcinterface,srcip,dstinterface和dstip' ...那里的值应该是'srsinterface = outside,srcip = 182.201.183.178,dstinterface = outside和dstip = 125.22.32.192' ... – aProgrammer

回答

1

用这个代替:

/^src(?> (\w++):((?>[0-9]{1,3}\.){3}[0-9]{1,3})(?>\/([0-9]++))?)?/ 

一个示例脚本:

#!/usr/bin/perl 

use strict; 

my $str = "src 
src LAN:10.115.1.204 
src LAN:10.115.1.204/8080"; 
my $i = 0; 
while($str =~ /^src(?> (\w++):((?>[0-9]{1,3}\.){3}[0-9]{1,3})(?>\/([0-9]++))?)?/gm) { 
print "\n[match " . ++$i . "]" 
    . "\nWhole match : $&" 
    . "\nCapture group 1: $1" 
    . "\nCapture group 2: $2" 
    . "\nCapture group 3: $3\n"; 
} 

对于一个更宽松的模式,您可以使用此:

/^src(?> (\w++):([^\/\n]++)(?>\/([^\n]++))?)?/gm 

或者这个:

/^src(?> (\w++):([^\/\n]++)(?>\/(\S++))?)?/gm 

的想法对于这些图案是用否定的字符类,例如[^\/\n]意味着所有不属于斜线或换行符字符。您可以轻松地将这些类适应您添加或删除角色的需求。

+0

所有格量词'++'和'(?> ...)'在这里毫无意义。 – Borodin

+0

鲍罗廷:我使用它们作为一个良好的习惯,因为你获得了最高性能的模式。你可以用'(?:..)'和'+'得到相同的结果,但是慢一点。 –

+1

我建议你写一个基准来比较两者。你所取得的成就是每个不熟悉Perl正则表达式的人都很困惑。 – Borodin

1

我没有Perl的大师,但也许这个工程:

($srcinterface,$srcip,$src_port) = m/^src\s*(?:(.*?):(.*?)(?:\/(.*?))?)?/; 

?:应该让一个隐藏组,?在一组的最后使得可选。

好,可读性进入疯狂......

+1

不幸的是这是行不通的... – aProgrammer

1

目前尚不清楚哪些字段是可选的,但是你可以简单地划分在正则表达式来分开什么是存在的。

在此程序中,@fields数组将包含与指定的数量相同的字段。假设可选字段从右侧消失(即,没有源地址没有接口名称,没有源端口没有名称和地址),您可以简单地计数@fields中的字段以查看提供的内容。

use strict; 
use warnings; 

use Data::Dump; 

for (
    'src', 
    'src LAN:10.115.1.204', 
    'src LAN:10.115.1.204/8080') { 

    my @fields = split /[\/\s]+/; 

    dd \@fields; 
} 

输出

["src"] 
["src", "LAN:10.115.1.204"] 
["src", "LAN:10.115.1.204", 8080] 
+0

[]内的字段是可选的 – aProgrammer

+0

@Amit:这意味着您的行可以只是'src'或完整' src局域网:10.115.1.204/8080',其间的任何内容都不正确。但是您的示例数据包含一条只包含*部分*信息的行,所以这必须是错误的。 – Borodin

+0

请查看输入字符串 – aProgrammer

1

此正则表达式为我工作

($srcinterface, $srcip, $src_port) = [email protected]^src (?:([^:]+):([^/]+))?(?(1)(?:/(.+))?)@; 

注:

  • 我使用的是否定的字符类(如[^:])和+,因为.*?会导致变体2和3出现问题,因为.*?后面的正则表达式没有很好地定义(简单地说,.*?会匹配零长度的字符串)。

  • 我提出的接口名称:source_address部分任选与一个封闭(?:...)?

  • 然后我用条件的正则表达式(?(1)pattern)这意味着“匹配pattern如果捕获组1匹配成功”

    有效地,如果interface_name:source_address与匹配,请寻找/port

  • 由于/端口是可选的,我包裹在里面条件的正则表达式中的另一个(?:...)?的部分。

对于它的价值,我觉得Borodin's split-based answer方式简单,Casimir et Hippolyte's regex-based answer是在稳健性方面更好,因为它实际上验证每个组件。我只是为了完成而发布这个。

+0

感谢您的答案.. – aProgrammer