Regex 正则表达式仅匹配有效行

Regex 正则表达式仅匹配有效行,regex,perl,Regex,Perl,我写了一个脚本,总结了很长的日志文件。我遇到的一个小问题是日志很容易有损坏的条目,因此我的摘要有时会包含一些不好的行。 我的脚本生成一个中间临时文件,我只需要从中选择有效的行 以下行有效,我需要匹配以下行: 21/05/14 09:17 134U 0993 EUser_Message 01 21/05/14 11:07 134UD 0994 User_Message B02 21/05/14 11:47 134P 09

我写了一个脚本,总结了很长的日志文件。我遇到的一个小问题是日志很容易有损坏的条目,因此我的摘要有时会包含一些不好的行。 我的脚本生成一个中间临时文件,我只需要从中选择有效的行

以下行有效,我需要匹配以下行:

21/05/14 09:17 134U 0993 EUser_Message 01 21/05/14 11:07 134UD 0994 User_Message B02 21/05/14 11:47 134P 0995 User_Message UOD1 21/05/14 12:41 134B18 0996 User_Message UOD2 21/05/14 14:00 134B 0997 User_Message T02 21/05/14 14:22 134NV 0998 User_Message D02 21/05/14 15:25 121U 0999 EUser_Message 03 21/05/14 16:38 121UD 1000 EUser_Message 04 22/05/14 07:39 134TP 1001 EUser_Message 08 22/05/14 09:55 134P 1002 EUser_Message 13 22/05/14 10:46 134B 1003 EUser_Message 14 22/05/14 12:00 134NonVac 1004 User_Message UOD3
如果有人能告诉我如何正确构建一个只匹配上面显示的有效文本行的正则表达式,我将不胜感激。

让我们准确地翻译一下:

(2位)(正斜杠)(2位)(正斜杠)(2位)(3个空格)(2位)(冒号)(2位)(3个空格)(4到9个字母或数字)(1到6个空格)(4位)(4个空格)(“用户信息字符串”)(0或1个空格)(新行)

现在唯一匹配的一行,你说你不想

17/04/14   10:04   134TP   0869    EUser_Message 01
我不明白为什么不应该符合你描述的规则

我猜这是因为您希望(4到9个字母或数字)和(1到6个空格)的总和始终为10个字符。我们可以使用-
(?=.{10}\b\d)

给我们最后的答案:

/^\d{2}\/\d{2}\/\d{2} {3}\d{2}:\d{2} {3}(?=.{10}\b\d)\w{4,9} {1,6}\d{4} {4}E?User_Message ?/

让我们准确地翻译一下:

(2位)(正斜杠)(2位)(正斜杠)(2位)(3个空格)(2位)(冒号)(2位)(3个空格)(4到9个字母或数字)(1到6个空格)(4位)(4个空格)(“用户信息字符串”)(0或1个空格)(新行)

现在唯一匹配的一行,你说你不想

17/04/14   10:04   134TP   0869    EUser_Message 01
我不明白为什么不应该符合你描述的规则

我猜这是因为您希望(4到9个字母或数字)和(1到6个空格)的总和始终为10个字符。我们可以使用-
(?=.{10}\b\d)

给我们最后的答案:

/^\d{2}\/\d{2}\/\d{2} {3}\d{2}:\d{2} {3}(?=.{10}\b\d)\w{4,9} {1,6}\d{4} {4}E?User_Message ?/

列之间的确切空格数可能相关,也可能无关。如果这应该是固定宽度字段数据,那么应该使用

有效的日志行必须有六个(或五个)字段,包括:

  • 约会
  • 一段时间
  • 某种标识符
  • 另一个标识符
  • 消息标识符
  • 另一个标识符
  • 使用unpack,您可以使用
    unpack'A11 A9 A11 A9 A20',$line
    提取字段。您仍然可以单独验证这些字段

    您应该提取每个字段并分别进行验证,而不是用一个正则表达式模式来管理它们

    下面是一个独立的示例。它假定字段提取采用空间分隔的数据,但对于固定宽度的字段数据,它的工作方式几乎相同,只需将
    拆分
    替换为
    解包
    ,并计算出字段的正确编号和名称

    我留下了一些验证器供您填写我对您的问题描述的理解中给定的不确定性

    有更多的方法来做这类事情,比如从组成部分构建一个大型正则表达式模式。但是,在我看来,你有空格分隔的列,有时六个单独的小检查的认知负担比一个正则表达式要轻

    此外,这使得添加进一步的代码来检查日期是否真的是有效日期、是否在某些范围内等变得更容易,而不会挤出程序的实际流程

    #!/usr/bin/env perl
    
    use strict;
    use warnings;
    
    package My::LogEntry;
    
    use Carp qw( croak );
    use Moo;
    
    my @fields = qw( date time field3 field4 msg_type field6 );
    has $_ => (is => 'ro', trigger => 1) for @fields;
    
    sub _trigger_date {
        my $self = shift;
        my $date = shift;
        unless ($date =~ m{\A [0-9]{2} / [0-9]{2} / [0-9]{2} \z}x) {
            croak "Invalid date '$date'";
        }
        return;
    }
    
    sub _trigger_time {
        my $self = shift;
        my $time = shift;
        unless ($time =~ m{\A [0-9]{2} : [0-9]{2} \z}x) {
            croak "Invalid time '$time'";
        }
        return;
    }
    
    sub _trigger_field3 {}
    
    sub _trigger_field4 {}
    
    sub _trigger_msg_type {
        my $self = shift;
        my $msg_type = shift;
        unless ($msg_type =~ m{ \A E? User_Message \z }x) {
            croak "Invalid message type '$msg_type'";
        }
        return;
    }
    
    sub _trigger_field6 {}
    
    sub do_something { }
    
    sub BUILDARGS {
        my $class = shift;
        unless (@fields == @_) {
            croak sprintf(
                '%s constructor called with %d args (%s), need %d',
                $class,
                scalar @_,
                join(',', @_),
                scalar @fields
            );
        }
        my $ret = {
            map +( $fields[$_] => $_[$_] ), 0 .. $#_
        };
    }
    
    while (my $line = <DATA>) {
        my @entry = split ' ', $line;
        my $entry;
        eval { $entry = My::LogEntry->new(@entry) };
        if ( $entry ) {
           $entry->do_something;
        }
        else {
           warn "$.: $@";
        }
    }
    
    __DATA__
    21/05/14   09:17   134U      0993    EUser_Message 01
    21/05/14   11:07   134UD     0994    User_Message B02
    21/05/14   11:47   134P      0995    User_Message UOD1
    21/05/14   12:41   134B18    0996    User_Message UOD2
    21/05/14   14:00   134B      0997    User_Message T02
    21/05/14   14:22   134NV     0998    User_Message D02
    21/05/14   15:25   121U      0999    EUser_Message 03
    21/05/14   16:38   121UD     1000    EUser_Message 04
    22/05/14   07:39   134TP     1001    EUser_Message 08
    22/05/14   09:55   134P      1002    EUser_Message 13
    22/05/14   10:46   134B      1003    EUser_Message 14
    22/05/14   12:00   134NonVac 1004    User_Message UOD3
    User_Message UOD1
    19/08/14   11:46   1388    EUser_Message 01
    03/07/13   0645    03/07/13   0646    03/07/13   0647    03/07/13   15:36   134U    0648
    0862    17/04/14   0866    17/04/14   0867    17/04/14   0868    17/04/14
    17/04/14   10:04   134TP   0869    EUser_Message 01
    21/05/14   14:02   134B    0982
    0983    22/05/14   22/05/14   12:48   134U    0984    User_Message UOD1
    1015    03/06/14
    11/07/13   08:12   134B    0011
    11/07/13   12:39   134B    0012
    11/07/13   13:53   134B    0013
    12/07/13   08:01   134P    0014
    12/07/13   08:29   134B    0015
    
    #/usr/bin/env perl
    严格使用;
    使用警告;
    包My::LogEntry;
    使用鲤鱼qw(croak);
    使用Moo;
    my@fields=qw(日期时间字段3字段4消息类型字段6);
    对于@fields,具有$979;=>(is=>'ro',触发器=>1);
    子触发日期{
    我的$self=shift;
    我的$date=班次;
    除非($date=~m{\A[0-9]{2}/[0-9]{2}/[0-9]{2}\z}x){
    croak“无效日期'$date'”;
    }
    返回;
    }
    子触发时间{
    我的$self=shift;
    我的$time=shift;
    除非($time=~m{\A[0-9]{2}:[0-9]{2}\z}x){
    哼唱“无效时间'$time'”;
    }
    返回;
    }
    子触发器字段3{}
    子触发器字段4{}
    子触发器消息类型{
    我的$self=shift;
    my$msg_type=班次;
    除非($msg_type=~m{\A E?User_Message\z}x){
    croak“无效的消息类型'$msg_type'”;
    }
    返回;
    }
    子触发器字段6{}
    sub do_something{}
    子构建参数{
    我的$class=shift;
    除非(@fields==@){
    呱呱(
    用%d个参数(%s)调用了“%s”构造函数,需要%d个参数,
    $class,
    标量,,
    连接(',',@)),
    标量@字段
    );
    }
    我的$ret={
    映射+($fields[$\u]=>$\u[$\ u]),0$#_
    };
    }
    while(我的$line=){
    my@entry=拆分“”,$line;
    我的$entry;
    eval{$entry=My::LogEntry->new(@entry)};
    如果($分录){
    $entry->dou_某事;
    }
    否则{
    警告“$:$@”;
    }
    }
    __资料__
    2014年5月21日09:17 134U 0993 EUser_信息01
    2014年5月21日11:07 134UD 0994用户信息B02
    2014年5月21日11:47 134P 0995用户信息UOD1
    2014年5月21日12:41 134B18 0996用户信息UOD2
    2014年5月21日14:00 134B 0997用户信息T02
    2014年5月21日14:22 134NV 0998用户信息D02
    2014年5月21日15:25 121U 0999 EUser_信息03
    2014年5月21日16:38 121UD 1000 EUser_信息04
    2014年5月22日07:39 134TP 1001 EUser_信息08
    2014年5月22日09:55 134P 1002 EUser_信息13
    2014年5月22日10:46 134B 1003 EUser_信息14
    2014年5月22日12:00 1344 AC 1004用户信息UOD3
    用户信息UOD1
    14年8月19日11:46 1388 EUser_信息01
    03/07/13 0645 03/07/13 0646 03/07/13 0647 03/07/13 15:36 134U 0648
    0862    17/04/14   0866    17/04/14   0867    17/04/14   0868    17/04/14
    2014年4月17日10:04 134TP 0869 EUser_信息01
    2014年5月21日14:02 134B 0982
    0983 22/05/14 22/05/14 12:48 134U 0984用户信息UOD1
    1015    03/06/14
    11/07/13 08:12 134B 0011
    11/07/13 12:39 134B 0012
    11/07/13 13:53 134B
    
    #!/usr/bin/env perl
    
    use strict;
    use warnings;
    
    package My::LogEntry;
    
    use Carp qw( croak );
    use Moo;
    
    my @fields = qw( date time field3 field4 msg_type field6 );
    has $_ => (is => 'ro', trigger => 1) for @fields;
    
    sub _trigger_date {
        my $self = shift;
        my $date = shift;
        unless ($date =~ m{\A [0-9]{2} / [0-9]{2} / [0-9]{2} \z}x) {
            croak "Invalid date '$date'";
        }
        return;
    }
    
    sub _trigger_time {
        my $self = shift;
        my $time = shift;
        unless ($time =~ m{\A [0-9]{2} : [0-9]{2} \z}x) {
            croak "Invalid time '$time'";
        }
        return;
    }
    
    sub _trigger_field3 {}
    
    sub _trigger_field4 {}
    
    sub _trigger_msg_type {
        my $self = shift;
        my $msg_type = shift;
        unless ($msg_type =~ m{ \A E? User_Message \z }x) {
            croak "Invalid message type '$msg_type'";
        }
        return;
    }
    
    sub _trigger_field6 {}
    
    sub do_something { }
    
    sub BUILDARGS {
        my $class = shift;
        unless (@fields == @_) {
            croak sprintf(
                '%s constructor called with %d args (%s), need %d',
                $class,
                scalar @_,
                join(',', @_),
                scalar @fields
            );
        }
        my $ret = {
            map +( $fields[$_] => $_[$_] ), 0 .. $#_
        };
    }
    
    while (my $line = <DATA>) {
        my @entry = split ' ', $line;
        my $entry;
        eval { $entry = My::LogEntry->new(@entry) };
        if ( $entry ) {
           $entry->do_something;
        }
        else {
           warn "$.: $@";
        }
    }
    
    __DATA__
    21/05/14   09:17   134U      0993    EUser_Message 01
    21/05/14   11:07   134UD     0994    User_Message B02
    21/05/14   11:47   134P      0995    User_Message UOD1
    21/05/14   12:41   134B18    0996    User_Message UOD2
    21/05/14   14:00   134B      0997    User_Message T02
    21/05/14   14:22   134NV     0998    User_Message D02
    21/05/14   15:25   121U      0999    EUser_Message 03
    21/05/14   16:38   121UD     1000    EUser_Message 04
    22/05/14   07:39   134TP     1001    EUser_Message 08
    22/05/14   09:55   134P      1002    EUser_Message 13
    22/05/14   10:46   134B      1003    EUser_Message 14
    22/05/14   12:00   134NonVac 1004    User_Message UOD3
    User_Message UOD1
    19/08/14   11:46   1388    EUser_Message 01
    03/07/13   0645    03/07/13   0646    03/07/13   0647    03/07/13   15:36   134U    0648
    0862    17/04/14   0866    17/04/14   0867    17/04/14   0868    17/04/14
    17/04/14   10:04   134TP   0869    EUser_Message 01
    21/05/14   14:02   134B    0982
    0983    22/05/14   22/05/14   12:48   134U    0984    User_Message UOD1
    1015    03/06/14
    11/07/13   08:12   134B    0011
    11/07/13   12:39   134B    0012
    11/07/13   13:53   134B    0013
    12/07/13   08:01   134P    0014
    12/07/13   08:29   134B    0015
    
    #!/usr/bin/perl
    use strict;
    use warnings;
    use Time::Piece; 
    
    while ( <DATA> ) {
       my ( $date, $time, $somecode, $othercode, $msgtype, $msgcode ) = split;
    
       if ( $date =~ m,^\d+/\d+/\d+$, 
       and $time =~ m,^\d+:\d+$, 
       and eval { Time::Piece->strptime("$date $time", "%d/%m/%y %H:%M") } ) {
           print "Date is ok\n";
       }
       else { print "$date $time is invalid\n"; next; }
    
       if ( $somecode =~ m/^\w+\d+$/ ) {  
           print "somecode is ok\n";
       }
       else {
           print "Error with somecode $somecode\n";
       }
    
       if ( $othercode =~ m,^\d{4}$, ) {
           print "othercode is ok\n";
       }
       else { 
            print "Error with $othercode \n";
            next;
       }
    
       if ( $msgtype =~ m/User_Message/ 
       and $msgcode =~ m/\w+/ ) {
           print "$msgtype $msgcode ok\n";
       }
       else {
           print "Error with $msgtype $msgcode\n"; 
           next;
       }
    
       print "Line: $. is ok\n$_";
    }
    
    __DATA__
    21/05/14   09:17   134U      0993    EUser_Message 01    
    21/05/14   11:07   134UD     0994    User_Message B02   
    21/05/14   11:47   134P      0995    User_Message UOD1   
    21/05/14   12:41   134B18    0996    User_Message UOD2   
    21/05/14   14:00   134B      0997    User_Message T02   
    21/05/14   14:22   134NV     0998    User_Message D02   
    21/05/14   15:25   121U      0999    EUser_Message 03   
    21/05/14   16:38   121UD     1000    EUser_Message 04   
    22/05/14   07:39   134TP     1001    EUser_Message 08   
    22/05/14   09:55   134P      1002    EUser_Message 13  
    22/05/14   10:46   134B      1003    EUser_Message 14  
    22/05/14   12:00   134NonVac 1004    User_Message UOD3
    User_Message UOD1     
    19/08/14   11:46   1388    EUser_Message 01    
    03/07/13   0645    03/07/13   0646    03/07/13   0647    03/07/13   15:36   134U    0648      
    0862    17/04/14   0866    17/04/14   0867    17/04/14   0868    17/04/14  
    17/04/14   10:04   134TP   0869    EUser_Message 01      
    21/05/14   14:02   134B    0982    
    0983    22/05/14   22/05/14   12:48   134U    0984    User_Message UOD1  
    1015    03/06/14   
    11/07/13   08:12   134B    0011    
    11/07/13   12:39   134B    0012   
    11/07/13   13:53   134B    0013    
    12/07/13   08:01   134P    0014    
    12/07/13   08:29   134B    0015
    
    use strict;
    use warnings;
    
    use v5.14;    # For regex /a modifier
    use re '/a';  # Regex patterns match only ASCII characters
    
    my $template = 'A11 A8 A10 A8 A*';
    
    my @validation = (
        qr{^\d\d/\d\d/\d\d$},
        qr{^\d\d:\d\d$},
        qr{^[0-9A-Z]+$}i,
        qr{^\d+$},
        qr{^E?User_Message\s+\w+$},
    );
    
    my ($total, $n) = (0, 0);
    
    while ( <DATA> ) {
    
        ++$total;
    
        my @fields = unpack $template, $_;
    
        my $valid = 1;
        for my $i ( 0 .. $#fields ) {
            $valid = $fields[$i] =~ $validation[$i];
            last if not $valid;
        }
    
        if ( $valid ) {
            ++$n;
            print;
        }
    }
    
    
    print "\n$n valid records of $total\n";
    
    __DATA__
    21/05/14   09:17   134U      0993    EUser_Message 01
    21/05/14   11:07   134UD     0994    User_Message B02
    21/05/14   11:47   134P      0995    User_Message UOD1
    21/05/14   12:41   134B18    0996    User_Message UOD2
    21/05/14   14:00   134B      0997    User_Message T02
    21/05/14   14:22   134NV     0998    User_Message D02
    21/05/14   15:25   121U      0999    EUser_Message 03
    21/05/14   16:38   121UD     1000    EUser_Message 04
    22/05/14   07:39   134TP     1001    EUser_Message 08
    22/05/14   09:55   134P      1002    EUser_Message 13
    22/05/14   10:46   134B      1003    EUser_Message 14
    22/05/14   12:00   134NonVac 1004    User_Message UOD3
    User_Message UOD1
    19/08/14   11:46   1388    EUser_Message 01
    03/07/13   0645    03/07/13   0646    03/07/13   0647    03/07/13   15:36   134U    0648
    0862    17/04/14   0866    17/04/14   0867    17/04/14   0868    17/04/14
    17/04/14   10:04   134TP   0869    EUser_Message 01
    21/05/14   14:02   134B    0982
    0983    22/05/14   22/05/14   12:48   134U    0984    User_Message UOD1
    1015    03/06/14
    11/07/13   08:12   134B    0011
    11/07/13   12:39   134B    0012
    11/07/13   13:53   134B    0013
    12/07/13   08:01   134P    0014
    12/07/13   08:29   134B    0015
    
    21/05/14   09:17   134U      0993    EUser_Message 01
    21/05/14   11:07   134UD     0994    User_Message B02
    21/05/14   11:47   134P      0995    User_Message UOD1
    21/05/14   12:41   134B18    0996    User_Message UOD2
    21/05/14   14:00   134B      0997    User_Message T02
    21/05/14   14:22   134NV     0998    User_Message D02
    21/05/14   15:25   121U      0999    EUser_Message 03
    21/05/14   16:38   121UD     1000    EUser_Message 04
    22/05/14   07:39   134TP     1001    EUser_Message 08
    22/05/14   09:55   134P      1002    EUser_Message 13
    22/05/14   10:46   134B      1003    EUser_Message 14
    22/05/14   12:00   134NonVac 1004    User_Message UOD3
    
    12 valid records of 25
    
    my @validation = (
        qr{^$RE{time}{tf}{ -pat => 'd/m/yy' }$},
        qr{^$RE{time}{tf}{ -pat => 'h:m' }$},
        qr{^[0-9A-Z]+$}i,
        qr{^\d+$},
        qr{^E?User_Message\s+\w+$},
    );