Perl:文件搜索正则表达式多行多个信息

时间:2016-06-25 00:04:37

标签: regex perl file

您好,我有一个文件,多行,我希望能够获取用户名和他正在使用的版本。

文件

<W>2016-06-25 00:27:30.577 1 => <4:(-1)> Client version 1.2.10 (Win: 1.2.10)
<W>2016-06-25 00:27:30.635 1 => <4:[AAA] User1(1850)> Authenticated
<W>2016-06-25 00:27:30.635 1 => <2:(-1)> Client version 1.2.16 (Win: 1.2.16)
<W>2016-06-25 00:27:30.687 1 => <2:[AAA] User2(942)> Authenticated

Outpout想要

4 : User1 : 1.2.10
2 : User2 : 1.2.16

所以一个客户的数据是2行。

  • 第一行获取版本号。
  • 第二行是用户名。

我注意到两行都有匹配ID,在我的例子中,user1行匹配ID为4:2:对于第二个用户。

所以我开始使用类似的东西,但是并没有按预期工作,并且创建第二个读取以找到整个文件中的第二行太多/未经过优化。

Perl脚本

#!/usr/bin/perl
use strict;
use warnings;
my $file = 'mylogfile.log';
open (my $fl, '<:encoding(UTF-8)', $file)
        or die 'File not found';

while (my $row = <$fl>) {
        if ($row =~ m/\<(\d+).*\>\sclient\sversion\s(\d+.\d+.\d+)\s/i) {
                my $id = $1;
                my $vers = $2;
                while (my $row1 = <$fl>) {
                        if ($row1 =~ m/\<$id\:(.+)\(\d+\)\>/i) {
                                my $name = $1;
                                print "$id : $name : $vers\n";
                        }
                }
        }
}

如果有任何perl大师有想法,谢谢! : - )

3 个答案:

答案 0 :(得分:1)

我在您的日志文件中看到相应行的时间戳不同。 所以,我想,当两个用户同时登录时,日志记录可能会散布,例如:

<W>2016-06-25 00:27:30.577 1 => <4:(-1)> Client version 1.2.10 (Win: 1.2.10)
<W>2016-06-25 00:27:30.635 1 => <2:(-1)> Client version 1.2.16 (Win: 1.2.16)
<W>2016-06-25 00:27:30.635 1 => <4:[AAA] User1(1850)> Authenticated
<W>2016-06-25 00:27:30.687 1 => <2:[AAA] User2(942)> Authenticated

如果是这种情况,我建议使用散列来记住id:

use strict;
use warnings;
my $file = 'mylogfile.log';
open (my $fl, '<:encoding(UTF-8)', $file)
        or die 'File not found';
my %ids;

while (my $row = <$fl>) {
        if ($row =~ m/\<(\d+).*\>\sclient\sversion\s(\d+.\d+.\d+)\s/i) {
        my ($id,$vers)=($1,$2);
        $ids{$id}=$vers;
    }
    elsif ($row =~ m/\<(\d+)\:(.+)\(\d+\)\>.*authenticated/i) {
        if (defined $ids{$1}) {
            print "$1 : $2 : $ids{$1}\n";
            delete $ids{$1};
        }
    }
}

答案 1 :(得分:0)

我对perl一无所知,但可以提供一些想法:

login= map();
while( row=readrow())
{
   if(match(id version))
     login[$1]=$2
   else
   if(match(id username userid ))
   {
     print "user: ", $2,  "version:",login[$1], "userid: $3", "sessionid: ", $1
     delete login[$1]
   }
}

答案 2 :(得分:0)

运行代码给了我结果

4 : [AAA] User1 : 1.2.10

您的第二个正则表达式是捕获括号内的字母用户名。这不是您想要的输出。

第二个while循环耗尽文件的其余部分。而且,这不是你想要做的。

这是一个可以产生你想要的输出的程序。 (我在程序的顶部创建了一个文件。你不会使用它,而是打开文件'mylogfile.log',就像你在代码中一样。)

#!/usr/bin/perl
use strict;
use warnings;

open my $fh, '<', \<<EOF;
<W>2016-06-25 00:27:30.577 1 => <4:(-1)> Client version 1.2.10 (Win: 1.2.10)
<W>2016-06-25 00:27:30.635 1 => <4:[AAA] User1(1850)> Authenticated
<W>2016-06-25 00:27:30.635 1 => <2:(-1)> Client version 1.2.16 (Win: 1.2.16)
<W>2016-06-25 00:27:30.687 1 => <2:[AAA] User2(942)> Authenticated
EOF


while (<$fh>) {
    if (/<(\d+).+?Client version (\d+\.\d+\.\d+)/) {
        my ($id, $vers) = ($1, $2);

        # read next line and capture name
        if (<$fh> =~ /<$id\S+ ([^(]+)/) {
            my $name = $1;
            print join(" : ", $id, $name, $vers), "\n";
        }
    }
}

在我的第二个正则表达式中,作品[^(]+被称为否定类。它匹配非'左派'(1次或更多次)。这匹配文件行中的“User1”和“User2”。

更新:您可以找到有关字符类here的信息。

更新2:看看wolfrevokcats的回复,我看到他做了一个有效的观察,他的解决方案是更安全的。