регулярное выражение (как Perl) - PullRequest
0 голосов
/ 31 октября 2011

$ str1 = "ssh_2-4 ^ принять IN = ETH2 OUT = eth33 MAC = 00: d0: c9: 96: 62: c0: 00: 1c: f0: 98: 19: 57: 08: 00 SRC = 192.168.200.30 DST = 192.168.200.224 LEN = 48 TOS = 0x00 PREC = 0x00 TTL = 128 ID = 30546 DF PROTO = TCP SPT = 10159 DPT = 4319 ОКНО = 7300 RES = 0x00 SYN URGP = 0 ";

$ str2 = "ssh_2-4 ^ принять IN = ETH2 OUT = eth33 MAC = 00: d0: c9: 96: 62: c0: 00: 1c: f0: 98: 19: 57: 08: 00 SRC = 192.168.200.30 DST = 192.168.200.224 LEN = 48 TOS = 0x00 PREC = 0x00 TTL = 128 ID = 30546 DF PROTO = ICMP WINDOW = 7300 RES = 0x00 URGP = 0 ";

Мне нужно захватить:

для $ str1 ==> ssh_2-4, принять, ETH @, eth33, 192.168.200.30, 192.168.200.224, TCP, 10159, 4319

для $ str2 ==> ssh_2-4, принять, ETH @, eth33, 192.168.200.30, 192.168.200.224, ICMP

Я использую приведенное ниже регулярное выражение и очень хорошо работаю с $ str1, но не работаю с $ str2:

(\w*)\^(\w*).*IN=(\S*).*OUT=(\S*).*SRC=(\S* ).*DST=(\S*).*PROTO=(\S*).*SPT=(\d*).*DPT=(\d*).*

Какое регулярное выражение подходит для этой цели?

Ответы [ 4 ]

2 голосов
/ 31 октября 2011

Раскол мне показался бы более надежным и чистым. Например:

$str2=~  /^(.*?)\^(\w*)\s+(.*)$/;
my($version,$action,$args) = ($1,$2,$3);
my %argsmap =  split(/[= ]/, $args);
print "proto=$argsmap{'PROTO'} \n";

Отредактировано: я ошибочно предположил, что у каждого "поля" была пара key=value. Фиксированная версия:

  my(@args) = split(/ /,$str2);
  my($version,$action) = split(/\^/,shift @args);
  my %argsmap = map { $_ =~ /(.*)=(.*)/ ? ($1,$2) : ($_,'') } @args;
0 голосов
/ 31 октября 2011

Более расколотая версия, основанная на ответе leonbloy . Прямое разделение не будет работать из-за нечетного количества элементов. Поэтому вместо этого мы явно разделяем на = и допускаем, чтобы пустые значения были неопределенными, чтобы сохранить пары ключ / значение хеш-функции.

Код:

use strict;
use warnings;

my $str1="ssh_2-4^accept IN=ETH2 OUT=eth33 MAC=00:d0:c9:96:62:c0:00:1c:f0:98:19:57:08:00 SRC=192.168.200.30 DST=192.168.200.224 LEN=48 TOS=0x00 PREC=0x00 TTL=128 ID=30546 DF PROTO=TCP SPT=10159 DPT=4319 WINDOW=7300 RES=0x00 SYN URGP=0";
my $str2="ssh_2-4^accept IN=ETH2 OUT=eth33 MAC=00:d0:c9:96:62:c0:00:1c:f0:98:19:57:08:00 SRC=192.168.200.30 DST=192.168.200.224 LEN=48 TOS=0x00 PREC=0x00 TTL=128 ID=30546 DF PROTO=ICMP WINDOW=7300 RES=0x00 URGP=0";

my @data;
for my $str ($str1, $str2) {
    my %hash;
    # First we extract the "header"
    $str =~ s/^([^^]+)\^(\w+) // || die "Did not match header";
    $hash{'version'} = $1;
    $hash{'action'} = $2;

    # Now process the args
    for my $line (split ' ', $str) {
        my ($key, $val) = split /=/, $line;
        $hash{$key} = $val;
    }
    # Save the hash into an array
    push @data, \%hash;
}

for my $href (@data) {
    # Now output the selected elements from each hash
    my $out = join ", ",
        @$href{'version','action','IN','OUT','SRC','DST','PROTO'};
    if ($href->{'PROTO'} eq 'TCP') {
        $out = join ", ", $out, @$href{'SPT', 'DPT'};
    }
    print "$out\n";
}

Выход:

ssh_2-4, accept, ETH2, eth33, 192.168.200.30, 192.168.200.224, TCP, 10159, 4319
ssh_2-4, accept, ETH2, eth33, 192.168.200.30, 192.168.200.224, ICMP
0 голосов
/ 31 октября 2011

Жадные квантификаторы означают, что каждый раз, когда выражение сопоставляется, оно сопоставляет .* со всеми остальными символами в строке. Это означает, что каждый каждый раз, когда он соответствует, должен потреблять ввод, не может найти следующее выражение, а затем возвращается назад, пока это не произойдет. Это очень неэффективно.

Вместо этого вы хотите использовать не жадную форму: .*?. И затем, чтобы убедиться, что вы получили целые слова / ключи, вы можете использовать спецификатор разбивки слов: \b, например:

my $re 
    = qr/
        ([\w-]*) \^ (\w*) .*? 
        \bIN=(\S*)  .*?
        \bOUT=(\S*) .*?
        \bSRC=(\S*) .*?
        \bDST=(\S*) .*?
        \bPROTO=(\S*)
        (?: .*? 
            \bSPT=(\d*) 
            .*?
            \bDPT=(\d*)
        )?
    /x;

Теперь, поскольку у вас нет полей SPT и DPT в каждой строке, вы хотите сделать это соответствие условным (?:...)?

И это все, что мне нужно было сделать:

while ( <$data> ) {
    my @flds = m/$re/;
    print join( ',', grep { defined and length } @flds ), "\n"; 
}
0 голосов
/ 31 октября 2011
$str1="ssh_2-4^accept IN=ETH2 OUT=eth33 MAC=00:d0:c9:96:62:c0:00:1c:f0:98:19:57:08:00 SRC=192.168.200.30 DST=192.168.200.224 LEN=48 TOS=0x00 PREC=0x00 TTL=128 ID=30546 DF PROTO=TCP SPT=10159 DPT=4319 WINDOW=7300 RES=0x00 SYN URGP=0";
$str2="ssh_2-4^accept IN=ETH2 OUT=eth33 MAC=00:d0:c9:96:62:c0:00:1c:f0:98:19:57:08:00 SRC=192.168.200.30 DST=192.168.200.224 LEN=48 TOS=0x00 PREC=0x00 TTL=128 ID=30546 DF PROTO=ICMP WINDOW=7300 RES=0x00 URGP=0";

foreach my $i ($str1, $str2) {
    if ($i =~ /^(.+)\^(\w+)\s+IN=(\S+)\s+OUT=(\S+).*?SRC=(\S+)\s+DST=(\S+).*?PROTO=(\S+)(?:.*?SPT=(\d+)\s+DPT=(\d+))?/) {
        print "/1=$1/2=$2/3=$3/4=$4/5=$5/6=$6/7=$7/8=$8/9=$9\n";
    }
}

Это дает

/1=ssh_2-4/2=accept/3=ETH2/4=eth33/5=192.168.200.30/6=192.168.200.224/7=TCP/8=10159/9=4319
/1=ssh_2-4/2=accept/3=ETH2/4=eth33/5=192.168.200.30/6=192.168.200.224/7=ICMP/8=/9=

Захватывать детали SPT и DPT в дополнительный подкрепитель: (?:.*?SPT=(\d+)\s+DPT=(\d+))?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...